phpでのバックグラウンド処理@阿部
今回は、ちょっとイレギュラーな書き込みになります。
何故かは、過去ログを見ていただければわかっていただけるでしょう(苦笑)
では、早々に今日のネタである「phpでのバックグラウンド処理」について書いてみようと思います。
phpは、比較的新しい言語ですし、文法もCやC++に似ていることもあり、とっつきやすい言語でもあります。
ただ、重たい処理(多大なDB処理など)を行うと、ブラウザの動き自体も停滞してしまうのが、欠点ではあります。
そこで、バックグラウンド処理を・・・となるわけですが、LinuxとWindowsでは外部プログラム呼び出し時の挙動が違うため、WebサーバのOSを考慮に入れなければなりません。
phpにはsystem関数や、pctrl_xxxx系統の外部プログラム呼び出しはあります。
LinuxでもWindowsでも上記の関数は使えます。
ただし、Linuxではコマンドライン(Windowsで言う所のDOS窓)のレベルでマルチプロセスがサポートされてますから、
system( "php backgnd.php > /dev/null &" );
という風に、標準出力をNULにして末尾に「&」をつければ、簡単にバックグラウンド処理が実行できます。
(※出力先をNULLデバイスにするのは必須)
一方で、Windows上での外部呼出しでは、OSの設計自体がマルチプロセスを前提としてない部分があるため、ちょっとしたコツが必要です。
私が知っている方法としては、
- 「COM」クラスでWindowsScriptオブジェクトを作り、別スレッドとして動かす。
- WindowsAPIのCreateProcess関数を使い、別プロセスとして動かす。
という2種類があります。
「COM」クラスでのWindowsScriptオブジェクトによる外部プログラム実行は、
$shell = new COM( "WScript.Shell" );
$shell->Run( "php.exe backgnd.php" );
$shell = null;
という感じのコードで実現できます。
一方、WindowsAPIのCreateProcess関数による外部プログラム実行は、
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.cb=sizeof(si);
CreateProcess(NULL,(LPTSTR)"php.exe backgnd.php",NULL,NULL,FALSE,
NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
という感じです。
(Windows環境では円記号(バックスラッシュ)ですが、)
私が実験した環境では、WindowsScriptオブジェクトだと複数個のスレッドは走らなかったり、Runメソッド自体での起動が出来なかったりと、不都合な部分があるように思います。
私が実用になると思ったのは、CreateProcess関数を使った方法です。
CreateProcess関数を呼び出すコマンドライン用プログラムを書く必要はありますが、複数個のプロセス起動が出来ますし、Windows環境であれば確実に動作します。
ただ、ここで問題となるのは、php自体にはマルチプロセス管理をする仕組みが乏しいので、
- データベースなどを利用して、進行状況を記録する必要がある。
- JavaScriptなどで、定期的に進行状況をチェックするphpプログラムを呼ぶ必要がある。
などの工夫をしなければなりません。
おそらく、phpでシステム構築をする場合は、データベースとの連携をするケースが多いでしょうから、データベースを進捗状況管理に使うことになるかと思います。
その場合、バッググラウンドのプロセスを大量に起動してしまうと、データベースによってはコネクションの許容数をオーバーして、処理自体が出来なくなる可能性があります。
php自体には、データベースのコネクションプール機能がありませんので、複数個(しかも大量の個数)のバックグラウンド処理を行う際には、コネクションプール処理を作る必要があるでしょう。
(コネクションプールに関しては、今回は割愛します)
あと、複数端末からアクセスされるサーバで「バックグラウンド」処理を行う場合には、データ競合や衝突が発生しないようにしなければいけません。
いろいろな事に気を使う必要が多いバックグラウンド処理ですが、味方につければ有用であることに間違いはないので、みなさん頑張って実装しましょう(笑)