2010年 8月 27日 はてなブックマーク -
タグ: #PHP

PHPで最大N個のプロセスを並列に実行するクラスを作成しました。

マルチスレッドデザインパターン Thread-Per-Message にあたるようです。ただPHPにはスレッドがないので、プロセスで代用しています。また最大起動プロセス数を超えた時点で、親プロセスが待ってしまいます。

ProcessPerMessageクラスの概要

ProcessPerMessage() コンストラクタ(同時実行プロセス数と子プロセスの最大実行時間を指定できる)
invocation()新たなプロセスを起動する(実行する関数引数を指定する)
shutdown()プロセスの終了を待つ

使用例

<?php
declare(ticks=1); //ProcessPerMessageを利用するために必要
require_once("ProcessPerMessage.php");

//プロセスプール生成
$option = array('max_process' => 10,'child_max_runtime' => 120);
$pool = new ProcessPerMessage($option);

for($i = 0; $i < 500; $i++) {
  //プロセスの起動状況を表示
  $pool->dump();

  //プロセス起動
  $option = array('func' => 'readRss','args' => $i);
  $pool->invocation($option);
}

//プロセスの終了を待つ
$pool->shutdown();

//プロセスが実行する関数
function readRss($url) {
  $sleep = rand(2,10);
  sleep($sleep);
}

クラス本体

class ProcessPerMessage {
  
  //■ コンストラクタ
  function ProcessPerMessage($option) {
    //同時実行プロセス数
    $this->max_process = 10;
    if (isset($option['max_process'])) {
      $this->max_process = intval($option['max_process']);
    }
    
    //子プロセスの最大実行時間
    $this->child_max_runtime = 60; //1分
    if (isset($option['child_max_runtime'])) {
      $this->child_max_runtime = intval($option ['child_max_runtime']);
    }
    
    //起動中のプロセスID一覧
    $this->pids = array();
  }
  
  //■ 新しいプロセス起動
  function invocation($option) {
    $func = null;
    if (isset($option['func'])){
      $func = $option['func'];
    } else {
      trigger_error("関数を指定してください");
    }
  
    $args = null;
    if (isset($option['args'])){
      $args = $option['args'];
    }

    $pid = pcntl_fork();
    
    if ( $pid == -1 ) {
      trigger_error("プロセスの起動に失敗しました。");
      
    } else if ( $pid ) {
      // 親プロセス      
      $this->pids[ $pid ] = TRUE;
      
      //起動最大値を超えている場合は、子プロセスの終了を待つ
      if ( count( $this->pids ) >= $this->max_process ) {
	unset( $this->pids[ pcntl_waitpid( -1, $status, WUNTRACED ) ] );
      }
      
    } else {
      //子プロセス
      
      // 120 秒後に強制終了
      pcntl_alarm( $this->child_max_runtime );
      
      call_user_func($func, $args);
      exit;
    }
  }

  //■ 全ての処理が終了するまで待機  
  function shutdown() {
    while ( count( $this->pids ) > 0 ) {
      unset( $this->pids[ pcntl_waitpid( -1, $status, WUNTRACED ) ] );
    }
  }

  //■ デバッグ情報取得
  function getDebugInfo() {
    $msg = "-------\n";
    foreach($this->pids as $pid => $v) {
      $msg .= "$pid\n";
    }
    $msg .= "-------\n";
    return $msg;
  }

  //■ デバッグ情報表示
  function dump() {
    $msg = $this->getDebugInfo();
    echo($msg);
  }
}

PHP 最大N個のプロセスを並列実行 - nishimura_snの日記

pnctlオプションを付けてコンパイルしたPHPから利用できます。


1年前 | | 2010年 8月 27日 | このエントリーを含むはてなブックマーク