ここ数日、仕事の都合により、PHP で書かれたバックグラウンド プログラムをシリアル実行からパラレル実行に変更する必要がありました。これには、必然的にマルチスレッド/マルチプロセス関連のテクノロジが関与することになります。 PHP は成熟したマルチスレッド メカニズムを備えていないようですが、比較的成熟したマルチプロセス メカニズムを備えています。マルチプロセスプログラミングには必然的に IPC (プロセス間通信) が関係します。 PHP には、sysvshm、sysvsem、sysvmsg、shmop およびその他の拡張機能があり、これらは IPC に使用できます。 pcntl - プロセスの提供 関連操作関数 sysvsem - セマフォ、フルネーム システム V セムフォア、共有リソースにアクセスするプロセスの数を制限するために使用できます。通常は 1 に設定され、ミューテックス ロックとして使用されます。 sysvshm - 共有メモリ、フルネーム システム V 共有共有メモリの仕組みは、顧客コードのシリアル化と逆シリアル化の手間が省けるのが特徴で、変数レベルのアクセス制御は非常に使いやすく、初心者でも利用できる手法です。 shmop - 共有メモリ操作の拡張機能。sysvshm との違いは、ビットレベルの制御であり、手動のシリアル化と逆シリアル化が必要であることです。ただし、メモリが不足している場合、メモリの使用量が sysvshm よりも高くなります。 sysvmsg - メッセージ キュー、特殊な種類の共有メモリ。具体的な使用方法については、ここを参照してください。
以下はメモとして sysvsem を使用する例です。具体的な内容についてはコードを参照してください。ここでいくつかの重要な点に注意してください。
shm_attach メソッドと sem_get メソッドのキーは main に関連付けられている必要があります。共有メモリとセマフォはプロセス間で共有されるシステムレベルのリソースであるため、2 つのコンポーネントを同時に実行するのは面倒です。処理されないと、複数のインスタンス間で混乱が発生します。 親プロセスが子プロセスを待機している場合、ビジー待機により多くの CPU が消費されます。スリープを使用すると、ビジー待機を回避できます。 無制限の待機を避けるために、子プロセスを待機するときに親プロセスにタイムアウト メカニズムを持たせることが最善です。子プロセスのロジックは指定された場所で終了する必要があり、親プロセスのコードは実行できません。そうしないと、混乱が生じます。 。一般的な方法は、try catch を使用してサブプロセスのロジックをラップし、例外をキャッチした後に終了することです。
<?phpdefine('PROC_NUM', 12);define('SRC_NUM', 20);define('TIME_OUT', 60); // 父进程等待超时,单位:秒$arr = array();for ($i = 0; $i < SRC_NUM; ++$i) { $arr[] = $i;}$sArr = serialize($arr); echo "parent id: " . posix_getpid() . "\n"; // create share memory$nShmID = shm_attach(ftok(__FILE__, 'i') . + posix_getpid(), strlen($sArr) * 2); // 采用主进程id作为key的部分,避免主进程之间干扰if ($nShmID == FALSE) { die("Failed to create shm\n");} // write the array to the shared memory$nArrKey = 1;if (FALSE == shm_put_var($nShmID, $nArrKey, $arr)) { die('Failed to write array to shm');} // create semphore$nSemID = sem_get(posix_getpid(), 1); // 采用主进程id作为key,避免主进程之间干扰 // child process consume the data in the shmfor($i = 0; $i < PROC_NUM; ++$i) { $nPID = pcntl_fork(); if ($nPID == 0) { // child $arrProcess = array(); while (true) { sem_acquire($nSemID); // get the value $arrCur = shm_get_var($nShmID, $nArrKey); if (0 == count($arrCur) || $arrCur == FALSE) { // value out sem_release($nSemID); break; } $nVal = array_pop($arrCur); if (FALSE == shm_put_var($nShmID, $nArrKey, $arrCur)) { die('Failed to write array to shm'); } sem_release($nSemID); // simulate process value sleep(rand(1,3)); $arrProcess[] = $nVal; } echo "Child process " . posix_getpid() . " consume: "; echo implode(' ',$arrProcess) . "\n"; exit(0); // 子进程逻辑一定要在这里退出,不能执行父进程代码 }} // wait for childrenecho "wait children\n";$n = 0;$nStart = time();while ($n < PROC_NUM && (time() - $nStart < TIME_OUT)) { // 父进程等待有超时机制,避免无限等待 //echo "wait ... \n"; $nStatus = -1; $nPID = pcntl_wait($nStatus, WNOHANG); if ($nPID > 0) { echo "{$nPID} exit\n"; ++$n; } sleep(1); // 避免忙等} // clear shm//shm_detach($nShmID);sem_remove($nSemID);shm_remove($nShmID);echo "finished\n";?>
関連情報
PHP IPC: http://blog.csdn.net/eroswang/article/details/2195260
PHP IPC system v と shmop: http://liangfen1224.blog. 163.com/blog/static/72377647201111163317325/