はじめに
PHPからシェルコマンドを利用する際、&
をつけるだけでは並列実行にならない場合があるのでメモしておきます。
-
exec
shell_exec
system
は同じ特徴を持つものとして考えて、exec
のみを用いて検証します。 -
popen
proc_open
は同じ特徴を持つものとして考えて、popen
のみを用いて検証します。 -
>&2
>/dev/null
は同じ特徴を持つものとして考えて、>&2
のみを用いて検証します。
今回はOSX環境を用います。Linux環境でもおそらく同様ですが、Windows環境では大きく結果が変わることが予想されるので、環境を用意出来る方は検証していただけると助かります。
実験
以下に組み合わせ条件を示します。for
文の中で3,4回程度繰り返し実行し、かかった合計時間で並列実行されたかを判定します。
-
exec
を使うか?popen
を使うか? -
&
をつけるか?つけないか? -
>&2
をつけるか?つけないか?
結果
並列実行された
A
exec('php -r "sleep(1);" >&2 &');
B
popen('php -r "sleep(1);" &', 'rb');
C
popen('php -r "sleep(1);" >&2 &', 'rb');
並列実行されなかった
D
exec('php -r "sleep(1);"');
E
exec('php -r "sleep(1);" &');
F
exec('php -r "sleep(1);" >&2');
G
popen('php -r "sleep(1);"', 'rb');
H
popen('php -r "sleep(1);" >&2', 'rb');
考察
どうですか?E
が並列実行されないのは意外じゃないでしょうか?尤も、E
のようなコードを書いて並列実行を謳っているようなQiita記事を見かけることが何度かあったので、今回の投稿をさせていただいた、というところです。
なおB
に関しても、バッファが消化されずに溜まり続けるという問題がありそうです。A
かC
、しいて言えばA
が一番無難な書き方でしょう。逆に結果の読み出しが必要になる場合はB
も有効な選択肢になってくると言えそうです、この場合はpopen
ではなくproc_open
必須になりますが…