ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Let's PHPコミュの擬似的なマルチスレッド

  • mixiチェック
  • このエントリーをはてなブックマークに追加
すでに消されたトピックですが、画像の合成をimagemagickを使ってphpからsystem()で呼び出すというネタがありました。私はsystem()じゃなくてpopen()を使うべき書いた理由を小ネタとして書いておきます。

(なお、system()を使うと提案した方に喧嘩を売るのが目的ではないことは明言しておきます。話の見通しをよくするためにsystem()関数の使用を提案したと私は解釈していますので。。。)

------------ mt.php ------------
<?php
define("LF","\n");
function f1(){
$start = microtime(true);
sleep(2);
$end = microtime(true);
return $end - $start;
}

function main(){
$start = microtime(true);
f1();
f1();
f1();
f1();
$fh = popen("php -f mtsub.php","r");
$out = '';
while(($buf = fread($fh,8192))){
$out .= $buf;
}
fclose($fh);
$end = microtime(true);
echo ($end - $start) . "sec (mtsub:" . $out ."sec)" LF;
}
main();
?>
-------------------------------

まあ、main()とするのは、私がC言語育ちからなんですけどね(苦笑)
(変数のスコープを限定したいので、明示的にこのように書いて、グローバル変数はグローバル変数で定義したほうが私としては理解しやすいので。。。)

要はsleep(2)を実行する関数を4回呼んで、計8秒消費します。
その後popen()で以下のphpを実行してさらに8秒消費させます。

---------- mtsub.php -----------
<?php
function main(){
$start = microtime(true);
sleep(8);
$end = microtime(true);
echo ($end - $start) . "sec" ;
}
main();
?>
-------------------------------

ここで、popen()位置を変更したmt2.phpと挙動の違いを比較して見ましょう。

------------ mt2.php ------------
<?php
define("LF","\n");
function f1(){
$start = microtime(true);
sleep(2);
$end = microtime(true);
return $end - $start;
}

function main(){
$start = microtime(true);
$fh = popen("php -f mtsub.php","r");
f1();
f1();
f1();
f1();
$out = '';
while(($buf = fread($fh,8192))){
$out .= $buf;
}
fclose($fh);
$end = microtime(true);
echo ($end - $start) . "sec (mtsub:" . $out ."sec)" LF;
}
main();
?>
-------------------------------

うちのatom230で実行すると

mt.phpは16秒、mt2.phpは8.23秒で実行されます。

この差は何かというと、popen()で別プロセスを開いたので、平行してmtsub.phpが実行されて約半分の時間で処理がすべて終了しました。

仮にpopen()じゃなくて、exec()を使うと、exec()の処理を待つので結局16秒かかります。
system()でもやはり処理の終了を待ってしまいます。

元ネタの話では、画像の生成が目的なので、こんなややこしいことを考えるメリットは無かったんですけど、実用レベルの話だと、画像の生成のほかにデータベースに何かしら書き込んだりなどその他の付随した処理があるはずなので、popen()でチャイルドプロセスを起こせば並行して処理を進められます。

もちろん、今回の例ではsleep()なので割りと理論値どおりの時間で処理できますけど、実際はディスクI/Oの処理とか親プロセスとチャイルドプロセスが独立して稼動できない状況というのは多々発生しますので本当に二つの処理が並行して動くわけではないです。

しかし、せっかくマルチコアCPUが当たり前の時代になったのですから、二つのコアにプログラマが意識して仕事を割り振るためにこういう小技を覚えておいても損はないと思います。

まあ、f1()の処理の結果がmtsub.phpに必要ではないということが絶対条件ではあるんですけどね。(^^;

逆にマルチコアを有効に使いたいなら、独立して動かせるようにプログラムのブロックきりわけやデータ構造の検討が必要になるのですが。

もっと大雑把に話をするとAjaxを積極的に取り入れれば、それだけでマルチプロセスになります。
(Ajaxで複数のリクエストを同時発行すれば、それはそのまま複数のHTTPセッションなので、マルチプロセスになります。それにAjaxならPHPでテンプレートエンジン使ってHTMLを生成することはなくなりますので、さらに効率よくサーバーを駆動させられます。)

※タイトルはマルチスレッドとか言っていますけど、中身はマルチプロセスなのはPHPだからということでご容赦ください。(^^;

コメント(0)

mixiユーザー
ログインしてコメントしよう!

Let's PHP 更新情報

Let's PHPのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング