PHP プロセス管理のコード例

不言
不言転載
2018-11-17 17:14:411911ブラウズ

この記事では、PHP プロセス管理に関するコード例を紹介します。一定の参考価値があります。困っている友人は参照してください。お役に立てば幸いです。

この記事は、前回の記事の補足と改良ですマスタープロセスを作成し、マスタープロセスにタイマーを設置し、5分ごとにキュー長を検出し、キュー長に基づいて計算します必要なワーカー プロセス、

#その後、子プロセスを作成または強制終了します。この利点は、キューが蓄積してタスクが時間内に処理されないことを防ぐことです。ビジネスコードを更新するには、リロード操作のみが必要です。

プロセス全体には次のナレッジ ポイントがあります:

  • デーモン プロセスを作成する手順:

  1. 設定 デフォルトのファイル権限

  2. プロセスをフォークすると、親プロセスが終了します

  3. setsid を呼び出して新しいセッションを作成します

  4. 現在の作業ディレクトリをルート ディレクトリに変更します

  5. 必要なくなったファイル記述子を閉じます

    ##シグナル実装タイマーを使用する
  • 前の記事のタイマーは、システムのスケジュールされたタスクに依存します。今回は、目覚まし時計シグナルを使用して実装されます。PHP 5.3.0 より前のバージョンはティックに依存しています。 5.3.0 以降のバージョンでは、pcntl_signal_dispatch を使用できます
#Signal: 非同期イベント処理のメソッドを提供します。シグナルが発生すると、プロセスには次の 3 つの方法でシグナルを処理します

#この信号を無視します

  1. 信号をキャプチャします

  2. システムのデフォルトのアクションを実行します。ほとんどの信号のデフォルトのアクションは、プロセス

  3. ##共通シグナル
    #SIGKILL と SIGSTOP は、ユーザーが無視したりキャプチャしたりできない 2 つのシグナルです
  • SIGINT( 2): プログラム終了信号。通常は Ctrl-C によって発行され、フォアグラウンド プロセス グループにプロセスを終了するように通知するために使用されます。

  • SIGQUIT(3): SIGINT と似ていますが、QUIT 文字によって行われます。 (通常は Ctrl /) コントロール。プロセスがこのメッセージを受け取って終了すると、コア ファイルが生成されます。

SIGKILL(9): プロセスをただちに終了し、無視したりブロックしたりすることはできません

SIGUSR1 (10): ユーザー定義信号

SIGUSR2(12): ユーザーに任せる

SIGALRM(14): アラームクロック信号

##SIGTERM(15): 終了プロセスをクリーンアップ操作を完了できるようにプログラムでキャプチャできます。

SIGSTOP(19): プロセスを停止します。プロセスはまだ終了していません。実行を一時停止しているだけです。

ゾンビ プロセスの生成を防止します

すべてのプロセスは、終了するとゾンビ プロセスになります。このとき、親プロセスがまだ実行中であり、wait または waitpid が呼び出されていない場合、ゾンビ プロセスが占有しているリソースはクリーンアップされません。親プロセスが終了すると、クリーンアップするために init. プロセスによってゾンビ プロセスが開始されます。
  • ビジネス コードをデプロイします。メイン コードは次のとおりです。

注意すべき点は、入力と出力を閉じるデーモン プロセスを作成するときにエラーが発生することです。出力ストリーム、コード出力文字の背後にエコーなどが存在する場合、致命的なエラーが発生するため、出力ストリームを PHP コード内で /dev/null にリダイレクトする必要があります。または、ターミナルがプロセスを開始するときにリダイレクトします。

<?php
define(&#39;PROC_MAX&#39;, 10);
define(&#39;PROC_MIN&#39;, 5);

$cmd = $argv[1];
$aPid = [];
$pidFile = __DIR__ . &#39;/pid.pid&#39;;
$pid = file_get_contents($pidFile);

switch($cmd){
    case &#39;start&#39; :
        if(posix_kill($pid, 0)){
            echo "gamelog process is already exsits!\n";
            return false;
        }
        //设置默认文件权限
        umask(022);
        //fork
        $pid = pcntl_fork();
        if($pid < 0){
            exit(&#39;fork error!&#39;);
        }else if($pid > 0){
            exit;
        }
        //脱离当前终端
        posix_setsid();
        //将当前工作目录更改为根目录
        chdir(&#39;/&#39;);
        //关闭文件描述符
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
        //重定向输入输出
        global $STDOUT, $STDERR;
        $STDOUT = fopen(&#39;/dev/null&#39;, &#39;a&#39;);
        $STDERR = fopen(&#39;/dev/null&#39;, &#39;a&#39;);
        
        cli_set_process_title(&#39;gamelog:master&#39;);
        $pid = posix_getpid();
        file_put_contents($pidFile, $pid);
        //闹钟信号
        pcntl_signal(SIGALRM, function() use (&$aPid) {
            pcntl_alarm(300);
            $workerNum = mt_rand(1, 20);//此处检测你需要的进程数
            $daemonNum = count($aPid);
            
            ($workerNum > PROC_MAX) && ($workerNum = PROC_MAX);
            if($daemonNum < $workerNum){
                $procNum = $workerNum - $daemonNum;
                $procNum = max(PROC_MIN, $procNum);
                for($p = 1; $p <= $procNum; $p++){
                    $pid = pcntl_fork();
                    if ($pid < 0) {
                        exit(&#39;fork error!&#39;);
                    } else if ($pid == 0) {
                        cli_set_process_title(&#39;gamelog:worker&#39;);
                        while (true) {
                            //do your work
                            usleep(100);
                        }
                        exit();
                    } else {
                        $aPid[] = $pid;
                    }
                }
            }else if($daemonNum > $workerNum){
                $wokerNum = max($wokerNum, PROC_MIN);
                $killNum = $daemonNum - $workerNum;
                foreach($aPid as $key=>$pid){
                    if(posix_kill($pid, SIGKILL)){
                        unset($aPid[$key]);
                        if(--$killNum <= 0){
                            break;
                        }
                    }
                }
            }
        }, false);
        
        pcntl_signal(SIGUSR1, function() use (&$aPid, $pid){
            foreach($aPid as $key=>$chpid){
                if(!posix_kill($chpid, SIGKILL)){
                    echo "kill child $chpid faild\n";
                }
            }
            posix_kill($pid, SIGKILL);
        }, false);
        
        pcntl_signal(SIGUSR2, function() use (&$aPid, $pid){
           foreach($aPid as $key=>$chpid){
                if(!posix_kill($chpid, SIGKILL)){
                    echo "kill child $chpid faild\n";
                }
            }
            if(!posix_kill($pid, SIGALRM)){
                echo "restart gamelog faild\n";
            }
        }, false);
        
        posix_kill($pid, SIGALRM);
        while (true) {
            pcntl_signal_dispatch();
            $pid = pcntl_wait($status, WUNTRACED);//不阻塞
        }
        break;
    
    case &#39;stop&#39; :
        if(!posix_kill($pid, SIGUSR1)){
            exit(&#39;stop gamelog process error!&#39;);
        }
        break;
    case &#39;reload&#39; :
        if(!posix_kill($pid, SIGUSR2)){
            exit(&#39;restop gamelog process error!&#39;);
        }
        break;
    default :
        echo "Useage php signal.php start|stop|reload\n";
}

以上がPHP プロセス管理のコード例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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