swoole_processがプロセス・プールを実現する方法の例


swoole――PHPの再定義
swooleのプロセスの間には2つの通信方式があります。一つはメッセージ・キュー(queue)、もう一つはパイプ(pipe)、対swoole(u)です。processの研究は特に重要です。
予備知識
IO多重化
swooleにおけるio多重化は下地層のepollプロセスモデルとして表現され,C言語ではepoll関数として表現された。
  • epollモデルの下で、自分の名義のsocket記述子fd
  • を継続的に監督します。
  • によって、socket傍受イベントがトリガされると、epoll関数は応答し、この時間を傍受するすべてのsocketセット
  • に戻る。
  • epollの本質はIOをブロックすることです。その利点は同僚が大量のsocket接続
  • を処理できることです。
    イベントループ
    swooleはepollに対してReactorスレッドモデルのパッケージを実現し、readイベントとwriteイベントのモニターコールバック関数を設定しました。詳しくはswoole_を参照してくださいイベントadd)
  • Event loopはReactorスレッドであり、ここではepollのインスタンスが実行されている。
  • swoole_を通過します。イベントaddは、socket記述子のイベントをepoll傍受に追加し、イベント発生時にはコールバック関数
  • を実行する。
  • は、fpmがタスク終了時にプロセスをオフにする可能性があるので、fpm環境では使用できません。
  • swoole_process
  • C言語パッケージに基づくプロセス管理モジュールは、便利phpにより
  • を起動する。
  • はパイプ、メッセージ・キュー・インターフェースを内蔵し、プロセス間通信
  • を容易にする。
    php-fpm.co nfプロファイルでは、php-fpmには2つのプロセスプール管理設定があることを発見しました。
  • 静止モードは、固定プロセス数を初期化し、要求が来たときに、プロセスを選択して処理する。
  • ダイナミックモードは、要求量が大きすぎて、プロセス数が最大制限を超えない場合、スレッド処理要求
  • を追加する。
    次にswooleコードで実現します。ここはswoole_を理解するためだけです。プロcess、プロセス間通信、タイマーなどが使用されていますが、実際にはパッケージされたswoole_を使用しています。serverはtaskタスクキュープールを実現するのに便利です。
    定時配達のジョブ待ち行列がある場合:
    
    <?php
    
    /**
     *      ,  fpm
     *       
     *       ,     ,            ,        
     */
    
    //           
    
    /**
     * 1. tick
     * 2. process      
     * 3. event loop     
     */
    class processPool
    {
      private $pool;
    
      /**
       * @var swoole_process[]     worker process  
       */
      private $workers = [];
    
      /**
       * @var array   worker    
       */
      private $used_workers = [];
    
      /**
       * @var int      
       */
      private $min_woker_num = 5;
    
      /**
       * @var int      
       */
      private $start_worker_num = 10;
    
      /**
       * @var int      
       */
      private $max_woker_num = 20;
    
      /**
       *         
       * @var int
       */
      private $idle_seconds = 5;
    
      /**
       * @var int      
       */
      private $curr_num;
    
      /**
       *        
       * @var array
       */
      private $active_time = [];
    
      public function __construct()
      {
        $this->pool = new swoole_process(function () {
          //     worker  
          for ($i = 0; $i < $this->start_worker_num; $i++) {
            $this->createWorker();
          }
          echo '      :' . $this->curr_num . PHP_EOL;
          //         worker        
          swoole_timer_tick(1000, function ($timer_id) {
            static $count = 0;
            $count++;
            $need_create = true;
            foreach ($this->used_workers as $pid => $used) {
              if ($used == 0) {
                $need_create = false;
                $this->workers[$pid]->write($count . ' job');
                //      
                $this->used_workers[$pid] = 1;
                $this->active_time[$pid] = time();
                break;
              }
            }
            foreach ($this->used_workers as $pid => $used)
              //     worker        ,     worker   
              if ($need_create && $this->curr_num < $this->max_woker_num) {
                $new_pid = $this->createWorker();
                $this->workers[$new_pid]->write($count . ' job');
                $this->used_workers[$new_pid] = 1;
                $this->active_time[$new_pid] = time();
              }
    
            //              
            foreach ($this->active_time as $pid => $timestamp) {
              if ((time() - $timestamp) > $this->idle_seconds && $this->curr_num > $this->min_woker_num) {
                //      
                if (isset($this->workers[$pid]) && $this->workers[$pid] instanceof swoole_process) {
                  $this->workers[$pid]->write('exit');
                  unset($this->workers[$pid]);
                  $this->curr_num = count($this->workers);
                  unset($this->used_workers[$pid]);
                  unset($this->active_time[$pid]);
                  echo "{$pid} destroyed
    "; break; } } } echo " {$count}/{$this->curr_num}
    "; if ($count == 20) { foreach ($this->workers as $pid => $worker) { $worker->write('exit'); } // swoole_timer_clear($timer_id); // $this->pool->exit(0); exit(); } }); }); $master_pid = $this->pool->start(); echo "Master $master_pid start
    "; while ($ret = swoole_process::wait()) { $pid = $ret['pid']; echo "process {$pid} existed
    "; } } /** * * @return int pid */ public function createWorker() { $worker_process = new swoole_process(function (swoole_process $worker) { // swoole_event_add($worker->pipe, function ($pipe) use ($worker) { $data = trim($worker->read()); if ($data == 'exit') { $worker->exit(0); exit(); } echo "{$worker->pid} {$data}
    "; sleep(5); // , $worker->write("complete"); }); }); $worker_pid = $worker_process->start(); // swoole_event_add($worker_process->pipe, function ($pipe) use ($worker_process) { $data = trim($worker_process->read()); if ($data == 'complete') { // // echo "{$worker_process->pid}
    "; $this->used_workers[$worker_process->pid] = 0; } }); // process $this->workers[$worker_pid] = $worker_process; // $this->used_workers[$worker_pid] = 0; $this->active_time[$worker_pid] = time(); $this->curr_num = count($this->workers); return $worker_pid; } } new processPool();
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。