[PHP-users 25215] Re: cli をデーモンとして使用する際の注意

komura komura @ ma9.seikyou.ne.jp
2005年 3月 31日 (木) 00:51:42 JST


komura です。
	
On Tue, 29 Mar 2005 14:23:02 +0900
Seiji Masugata <s.masugata @ digicom.dnp.co.jp> wrote:

> > この問題ですが、デーモンにするのであれば、pcntl_fork() を使用すること
> > で回避できないでしょうか?
> 
> 連絡が遅くなってしまいましたが試してみました。
> 個人的な感想ですが(使い方次第では)いけるのでは、と思いました。
> 
> (子プロセスに処理をまかせて、そちらのリソースを適時開放という事ですね)

私もこのような処理方法には興味がありますので、試していただけて嬉しいです。

私の方も Linux 環境で、PHP 4.3.10 と PostgreSQL 7.4.7 を使って同様のことを
試してみたのですが、残念ながらうまく動作しませんでした。

OS や PHP のバージョンなどの環境の問題もあるのかもしれません。
また、PHP マニュアルの User Contributed Notes には、pcntl_fork() の前に
MySQL のリソースを解放すべきという投稿もあります。

http://jp2.php.net/manual/ja/function.pcntl-fork.php#51217

どうやら、子プロセスの終了時に、データベースへの接続を解放してしまい、
次の接続が失敗してエラーが発生するようです。


代替手段として、以下のようなスクリプトを作成してみましたが、こちらはうまく
動作しているようです。子プロセスでデータベースへの接続を確立してからループ
させて、定期的に子プロセスを再起動という感じです。

while ( TRUE ) {
  $pid = pcntl_fork();
  if ( $pid === -1 ) {
    exit;
  }
  else if ( $pid ) {
    // 親プロセス
    pcntl_waitpid( -1, $status, WUNTRACED );
  }
  else {
    // 子プロセス
    $connect = pg_connect( 'dbname=test host=localhost port=5432' );

    $count = 0;
    while ( ++$count < 100 ) {
      $result = pg_query( 'SELECT * FROM test' );
      if ( ! $result ) {
        echo pg_last_error();
        exit;
      }
      $arr = pg_fetch_all( $result );
      echo "[" . date( "Y/m/d H:i:s" ) . "] SELECT => " . count( $arr ) . "\n";

      sleep( 5 );
    }
    exit;
  }
}


pcntl_fork() は何かの処理を並列で行いたい時に使うと便利だと思います。
個人的には、以下のように親プロセスで子プロセスの管理を行って並列処理
を行うのに使用したことがあります。

例えば、以下のように、外部の HTML を複数取得する時に子プロセスを複数
生成して並列に処理させると、待ち時間が少なくて済むと思います。


Apache モジュール版では pcntl_fork() は使用できませんので、あまり使う
ことはないかもしれませんが、何かの参考にでもなれば幸いです。

$uri_list = array(
 'http://example.com/',
// ...
)

// 生成する子プロセスの数
$children = 3;

$pids = array();

foreach ( $uri_list as $uri ) {
  $pid = pcntl_fork();
  if ( $pid === -1 ) {
    exit;
  }
  else if ( $pid ) {
    // 親プロセス
    $pids[$pid] = TRUE;
    if ( next( $uri_list ) === FALSE ) {
      $children = 1;
    }
    while ( count( $pids ) >= $children ) {
      $id = pcntl_waitpid( -1, $status, WUNTRACED );
      unset( $pids[$id] );
    }
  }
  else {
    // 子プロセス
    $html = file_get_contents( $uri );
    // ...
    exit;
  }
}
// 以下の処理は親プロセスで実行
// ...

-- 
komura <komura @ ma9.seikyou.ne.jp>


PHP-users メーリングリストの案内