プログラミング言語や環境設定を中心としたパソコン関連の技術メモです。
主にシステム開発中に調べたことをメモしています。TIPS的な位置付けで、気が向いたときにちまちま更新していきます。
PHP、一部の処理を別スレッドで実行する。
結論から書けば、PHPの「exec()」関数とUNIXコマンドの「nohup」を使って

exec("nohup php -c '' 'hoge.php' > /dev/null &");

とか書けばOKです。
「『nohup』って何じゃらほい?」な方は「nohup【コマンド】」辺りをご覧ください。

それでは細かく語っていきます(--)ノ

元々のきっかけは自前のウェブサービスでした。
実はこのWebサービス、ページの表示回数をカウントしていましてね。
ページを表示する度にDBの値をカウントアップしているのです。

ただ単純に作っちゃうと、DBの更新が終わるまでページが表示されないのですね。
処理が全部終わるまでレスポンスが返らないのです。

このDB更新の時間、ページを表示する分には必要無いじゃないですか。
別に大した時間が掛かるわけではないので無視しても良いのですが、
見てくれている人にとって無駄な時間だよなぁ、と考えました。
ページ自体はさっと表示してあげて、その後でゆっくりDBの値をカウントアップしたかったのです。

ってな経緯で、DB更新部分を別スレッドに分離することにヾ(´∀`)ノ

早速、調べてみますかな。
ふむふむ(--)

PHPの「exec()」関数とUNIXコマンドの「nohup」を使えばできるそうです。

実コードを晒すと余計な処理も入っているので、サンプルを作ってみました。
簡略化したサンプルコードがこちらφ(--)

■test.php
<?php

error_log(microtime() . ":main start\n", 3, dirname(__FILE__) . "/debug.log");

//別スレッドで処理呼び出し
exec("nohup php -c '' '" . dirname(__FILE__) . "/test_sub.php' > /dev/null &");

//1秒お休み
sleep(1);

error_log(microtime() . ":main end\n", 3, dirname(__FILE__) . "/debug.log");

print "finish";

■test_sub.php
<?php

error_log(microtime() . ":sub start\n", 3, dirname(__FILE__) . "/debug.log");

//2秒お休み
sleep(2);

error_log(microtime() . ":sub end\n", 3, dirname(__FILE__) . "/debug.log");

難しくは無いですよね?
メインの処理は「test.php」から「test_sub.php」を別スレッドで起動しているだけです。
確認用のログ出力部品を作るのが面倒だったので、エラーじゃないけど「error_log()」関数を使って
「debug.log」ファイルにログを出力しています。
「sleep()」はメインとサブの処理順を調整するために入れています。
処理順の紛れをなくすために入れているだけで深い意味はありません。

このサンプルコードを実行したところ、debug.logの中身はこんな感じになりましたφ(--)

0.54156700 1394522035:main start
0.56178100 1394522035:sub start
0.56303300 1394522036:main end
0.56475700 1394522037:sub end

メインが終わってもサブの処理が続いていますね。

ちなみに私の環境ではメインの「sleep(1)」を消すと

0.33922200 1394522297:main start
0.34983400 1394522297:main end
0.35950100 1394522297:sub start

0.36345800 1394522299:sub end

のように、メインの終了とサブの開始の順番が入れ替わっちゃいました。
恐らくサブの起動タイムラグの間にメインが終わっちゃったのでしょうね。
ただいずれにせよ、メインが終了してもサブは最後まで処理を行います。

そんな感じです(--)ノ


あっ、そうそう。
メインからサブに値を渡すこともできますよ。

exec("nohup php -c '' 'hoge.php' 'パラメータ1' 'パラメータ2' > /dev/null &");

のように「exec()」で呼び出す中身でパラメータを付与してやります。
パラメータは半角スペース区切りで複数書けますので、好きなだけ書いちゃってください。

実際に試せばすぐ分かると思いますけど、一応サンプルコードも置いておきますね。
例えばこんなコードを実行するとφ(--)

■test2.php
<?php

error_log(microtime() . ":main start\n", 3, dirname(__FILE__) . "/debug.log");

//別スレッドで処理呼び出し
//exec("nohup php -c '' '" . dirname(__FILE__) . "/test_sub2.php' > /dev/null &");
exec("nohup php -c '' '" . dirname(__FILE__) . "/test_sub2.php' 'p1' 'p2' > /dev/null &");

//1秒お休み
sleep(1);

error_log(microtime() . ":main end\n", 3, dirname(__FILE__) . "/debug.log");

print "finish";

■test_sub2.php
<?php

error_log(microtime() . ":sub start\n", 3, dirname(__FILE__) . "/debug.log");

//親処理からのパラメータ受け取り確認
error_log(microtime() . ":param0 = $argv[0]\n", 3, dirname(__FILE__) . "/debug.log");
error_log(microtime() . ":param1 = $argv[1]\n", 3, dirname(__FILE__) . "/debug.log");
error_log(microtime() . ":param2 = $argv[2]\n", 3, dirname(__FILE__) . "/debug.log");


//2秒お休み
sleep(2);

error_log(microtime() . ":sub end\n", 3, dirname(__FILE__) . "/debug.log");

debug.logの中身はこんな風になりますφ(--)

0.56721100 1394522594:main start
0.58467000 1394522594:sub start
0.58472700 1394522594:param0 = /home/hoge/public_html/test/test_sub2.php
0.58475700 1394522594:param1 = p1
0.58477200 1394522594:param2 = p2

0.58597000 1394522595:main end
0.58603000 1394522596:sub end

メインから渡されたパラメータは「argv[]」という配列に入ってサブに渡されます。
ただしargv[0]には呼び出されたスクリプト名が入っていますのでご注意ください。
実際のパラメータはargv[1]から始まります。

そんな感じです。
取りあえずこれで、私は自分のやりたかったことがやれました。

と言うわけで、PHPにおける処理の別スレッド化、完了\(--)/
スポンサーリンク
 
このエントリーをはてなブックマークに追加 

category:● PHP  thema:システム開発 - genre:コンピュータ  Posted by ササキマコト 

  関連記事