ホームページ >PHPフレームワーク >Laravel >PHPマルチプロセスとシグナル割り込みでマルチタスク常駐メモリ管理を実現【マスター/ワーカーモデル】

PHPマルチプロセスとシグナル割り込みでマルチタスク常駐メモリ管理を実現【マスター/ワーカーモデル】

藏色散人
藏色散人転載
2019-10-02 17:37:442512ブラウズ

この記事は、pcntl 拡張機能によって実行されたマルチプロセス テストに基づいています。

プロセス スケジューリング戦略

オペレーティング システムは、親プロセスと子プロセスのスケジューリングを担当します。子プロセスまたは親プロセスの具体的なスケジューリングは、最初に次のように決定されます。システムのスケジューリング アルゴリズム。もちろん、親プロセスを最初にスケジュールすることもできます。プロセスに遅延を追加するか、プロセス リサイクル関数 pcntl_wait を呼び出すと、子プロセスを最初に実行できます。プロセス リサイクルの目的は、プロセスのリサイクル時に占有されていたメモリ領域を解放することです。プロセスは、ゾンビプロセスになるのを防ぐために作成されます。

シグナル:

シグナルはソフト割り込みシステムまたはソフト割り込みと呼ばれ、その機能は非同期イベント通知をプロセスに送信することです。

シグナル番号: [ソースコードはSIGINT、SIGTERM、SIGUSR1シグナルに基づいています。意味についてはkillコマンドのマニュアルを確認してください。説明はありません]

Linux は 64 をサポートしており、そのうちの半分はリアルタイム信号です 半分は非リアルタイム信号です これらの信号には独自の番号と対応する整数値があります。各信号番号の意味については、関連する Linux マニュアルを参照してください [マニュアルを参照するとわかります]

信号処理関数:

Signals通常、対応する関数にバインドされていますが、SIGKILL、SIGTERM、SIGINT などのデフォルトのアクションを持つものもあります。デフォルトの操作はプロセスを強制終了することです。もちろん、pcntl_signal を介してオーバーライドすることでこれをオーバーライドできます。

信号の概念: ハードウェア割り込みと同じですので、以前の記事を参照するか、チップのハードウェア割り込みの原理を確認してください。

シグナル送信:

kill シグナル番号プロセスまたは主要製品の割り込みシグナル、またはソース コードで posix_kill およびその他の関数を使用できます。

プロセスは互いに分離されており、独自のスタック スペースを持っています。いくつかの共通のテキスト [コード領域] に加えて、独自の実行可能コードもあります。プロセスの実行中は CPU リソースを占有し、他のプロセスはそれにアクセスできません。実行する権利がありますが、この時点で他のプロセスはブロックされた状態になります (前述の TCP サービスなど)。プロセスが終了すると、[コードの最後の文まで実行するか、リターンに遭遇します。または終了、プロセス関数を終了するか、信号イベントが発生すると終了します] アクセス許可を放棄してメモリを解放すると、他のプロセスが実行される機会が得られます。

プロセスには独自のプロセス記述子があり、プロセス番号 PID がより一般的に使用されます。プロセスが実行されると、対応するプロセス ファイルがシステム /proc/PID の下に生成され、ユーザーは自分で見てください。

各プロセスには独自のプロセス グループ [プロセスの集合] があります。複数のプロセス グループの集合がセッションです。セッションの作成はプロセスを通じて作成され、このプロセスをグループ リーダー プロセスにすることはできません。プロセスは、セッション中にセッションの最初のプロセスとなり、プロセスグループのプロセスリーダーにもなり、同時に制御端末から離脱します。前のプロセスが制御端末にバインドされている場合でも、プロセスは離脱します。 [デーモンプロセスの作成]。

ファイル説明パーミッション マスク [パーミッション マスク ワード]:

umask () Linux でこのコマンドを実行し、ファイルを作成してそのパーミッションを表示できます [実行後に何も見つからない場合は、まだ十分なトレーニングができていないことを意味します^_^]

<?php
/**
 * Created by PhpStorm.
 * User: 1655664358@qq.com
 * Date: 2018/3/26
 * Time: 14:19
 */
namespace Chen\Worker;
class Server
{
    public $workerPids = [];
    public $workerJob = [];
    public $master_pid_file = "master_pid";
    public $state_file = "state_file.txt";
    function run()
    {
        $this->daemon();
        $this->worker();
        $this->setMasterPid();
        $this->installSignal();
        $this->showState();
        $this->wait();
    }
    function wait()
    {
        while (1){
            pcntl_signal_dispatch();
            $pid = pcntl_wait($status);
            if ($pid>0){
                unset($this->workerPids[$pid]);
            }else{
                if (count($this->workerPids)==0){
                    exit();
                }
            }
            usleep(100000);
        }
    }
    function showState()
    {
        $state = "\nMaster 信息\n";
        $state.=str_pad("master pid",25);
        $state.=str_pad("worker num",25);
        $state.=str_pad("job pid list",10)."\n";
        $state.=str_pad($this->getMasterPid(),25);
        $state.=str_pad(count($this->workerPids),25);
        $state.=str_pad(implode(",",array_keys($this->workerPids)),10);
        echo $state.PHP_EOL;
    }
    function getMasterPid()
    {
        if (file_exists($this->master_pid_file)){
            return file_get_contents($this->master_pid_file);
        }else{
            exit("服务未运行\n");
        }
    }
    function setMasterPid()
    {
        $fp = fopen($this->master_pid_file,"w");
        @fwrite($fp,posix_getpid());
        @fclose($fp);
    }
    function daemon()
    {
        $pid = pcntl_fork();
        if ($pid<0){
            exit("fork进程失败\n");
        }else if ($pid >0){
            exit(0);
        }else{
            umask(0);
            $sid = posix_setsid();
            if ($sid<0){
                exit("创建会话失败\n");
            }
            $pid = pcntl_fork();
            if ($pid<0){
                exit("进程创建失败\n");
            }else if ($pid >0){
                exit(0);
            }
            //可以关闭标准输入输出错误文件描述符【守护进程不需要】
        }
    }
    function worker()
    {
        if (count($this->workerJob)==0)exit("没有工作任务\n");
        foreach($this->workerJob as $job){
            $pid = pcntl_fork();
            if ($pid<0){
                exit("工作进程创建失败\n");
            }else if ($pid==0){
                /***************子进程工作范围**********************/
                //给子进程安装信号处理程序
                $this->workerInstallSignal();
                $start_time = time();
                while (1){
                    pcntl_signal_dispatch();
                    if ((time()-$start_time)>=$job->job_run_time){
                        break;
                    }
                    $job->run(posix_getpid());
                }
                exit(0);//子进程运行完成后退出
                /***************子进程工作范围**********************/
            }else{
                $this->workerPids[$pid] = $job;
            }
        }
    }
    function workerInstallSignal()
    {
        pcntl_signal(SIGUSR1,[__CLASS__,&#39;workerHandleSignal&#39;],false);
    }
    function workerHandleSignal($signal)
    {
        switch ($signal){
            case SIGUSR1:
                $state = "worker pid=".posix_getpid()."接受了父进程发来的自定义信号\n";
                file_put_contents($this->state_file,$state,FILE_APPEND);
                break;
        }
    }
    function installSignal()
    {
        pcntl_signal(SIGINT,[__CLASS__,&#39;handleMasterSignal&#39;],false);
        pcntl_signal(SIGTERM,[__CLASS__,&#39;handleMasterSignal&#39;],false);
        pcntl_signal(SIGUSR1,[__CLASS__,&#39;handleMasterSignal&#39;],false);
    }
    function handleMasterSignal($signal)
    {
        switch ($signal){
            case SIGINT:
                //主进程接受到中断信号ctrl+c
                foreach ($this->workerPids as $pid=>$worker){
                    posix_kill($pid,SIGINT);//向所有的子进程发出
                }
                exit("服务平滑停止\n");
                break;
            case SIGTERM://ctrl+z
                foreach ($this->workerPids as $pid=>$worker){
                    posix_kill($pid,SIGKILL);//向所有的子进程发出
                }
                exit("服务停止\n");
                break;
            case SIGUSR1://用户自定义信号
                if (file_exists($this->state_file)){
                    unlink($this->state_file);
                }
                foreach ($this->workerPids as $pid=>$worker){
                    posix_kill($pid,SIGUSR1);
                }
                $state = "master pid\n".$this->getMasterPid()."\n";
                while(!file_exists($this->state_file)){
                    sleep(1);
                }
                $state.= file_get_contents($this->state_file);
                echo $state.PHP_EOL;
                break;
        }
    }
}  
<?php
/**\
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;
class Job
{
  public $job_run_time = 3600;
  function run($pid)
 {\sleep(3);
  echo "worker pid = $pid job 没事干,就在这里job\n";
  }
}  
<?php
/**
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;
class Talk
{
  public $job_run_time = 3600;
  function run($pid)
 {\sleep(3);
  echo "worker pid = $pid job 没事干,就在这里talk\n";
  }
}
<?php
/**
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 15:45\ */
require_once &#39;vendor/autoload.php&#39;;
$process = new \Chen\Worker\Server();
$process->workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()];
$process->run();

PHPマルチプロセスとシグナル割り込みでマルチタスク常駐メモリ管理を実現【マスター/ワーカーモデル】

Laravel 関連の技術記事の詳細については、Laravel をご覧ください。フレームワーク入門チュートリアル 学習用コラム!

以上がPHPマルチプロセスとシグナル割り込みでマルチタスク常駐メモリ管理を実現【マスター/ワーカーモデル】の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。