2014年5月22日木曜日

PHPでマルチスレッドプログラミングをやってみた

■環境
CentOS release 5.10 (Final)
PHP 5.3.3

pcntlというモジュールが含まれている必要があります
以下のコマンドでチェックできるので含まれていない場合は「--enable-pcntl」をコンパイルオプションに指定し再度PHPをインストールし直して下さい
php -m | grep pcntl
pcntl

■サンプルコード
touch sampleMulti.php
emacs sampleMulti.php
$pscount = 0;
for ($i = 0; $i < 5; $i++) { 
    $pid = pcntl_fork();
    if ($pid == -1) {
      die('do not fork process');
    } else if ($pid) {
      // for parent process
      echo "parent process $pid \n";
      $pscount++;
    } else {
      // for child process
      echo "child process \n";
      sleep(10);
      echo "child process end \n";
      exit(0);
    }
}

while ($pscount >= 0) {
  pcntl_waitpid( -1, $status, WUNTRACED );
  $pscount--;
}

echo "end of all process \n";

★処理説明
pcntl_fork() を呼び出すと親プロセスに対して子プロセスが作成されます
子プロセスは if 文の else の方に入り 10 秒間待ちます
親プロセスは else if 分の方に入ります
$pscount は fork された子プロセスの数管理をします、子プロセスが作成されるたびに $pscount はインクリメントされていきます

pcntl はメインスレッドとは別で実行される非同期処理です、そのままだと子プロセスの終了を待たずして次の処理にどんどん進んでしまいます
なので、for の後に作成された子プロセスがすべて終了するまで待つロジックを入れてあげる必要があります
これを入れてあげないとプログラムはどんどん先に進んでしまい子プロセスが終了する前に親プロセス(実行したphpプロセス自体)が終了してしまい子プロセスが強制的に停止されてしまいます
なので子プロセス数を管理する $pscount を使って子プロセスの数が 0 になるまで待つようにしてあげています
(このあたりの待つロジックは別のサンプルもたくさんあるので実装しやすい方法で実装するといいと思います)

また、pcntl_waitpid に -1 の引数を渡すことで実行中の親プロセスにぶらさがっているすべての子プロセスの処理が完了するまで親プロセスを待たすことができます

■実行
php sampleMulti.php

実行中に pstree -ap コマンドでプロセスツリーを見てみましょう
php sampleMulti.php のコマンドの子プロセスとして5つのプロセスが存在していることがわかると思います
# pgrep php
30465
30466
30467
30468
30469
30470
# pstree -an 30465
php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php

今回のプログラムでは約 10 秒経過したあとに「end of all process」と表示されれば子プロセスおよび親プロセスが終了したことになります

■参考サイト

0 件のコメント:

コメントを投稿