這里說的異步執行是讓php腳本在后台掛起一個執行具體操作的腳本,主腳本退出后,掛起的腳本還能繼續執行。比如執行某些耗時操作或可以並行執行的操作,可以采用php異步執行的方式。主腳本和子腳本的通訊可以采用外部文件或memcached的方式。原理就是通過exec或system來執行一個外部命令。注意:本文所述的是針對Linux環境。
在Linux下要讓一個腳本掛在后台執行可以在命令的結尾加上一個 “&” 符號,有時候這還不夠,需要借助nohup命令,關於nohup,可以參考http://www.netingcn.com/linux-nohup.html。
CLI環境和Web環境執行的操作還不太一樣。先來說CLI環境,這里需要用上nohup和&,同時還要把指定輸出,如果不想要輸出結果,可以把輸出定向到/dev/null中。現在來做一個測試,假設在一個目錄中有main.php、sub1.php和sub2.php,其中sub1和sub2內容一樣都讓sleep函數暫停一段時間。代碼如下:
1 //main.php 2 <?php 3 $cmd = 'nohup php ./sub.php >./tmp.log &'; 4 exec($cmd); 5 $cmd = 'nohup php ./sub1.php >/dev/null &'; 6 exec($cmd); 7 ?> 8 9 //sub1.php sub2.php 10 <?php 11 sleep(100000); 12 ?>
上述文件中main.php是作為主腳本,在命令行中執行php main.php,可以看到main.php腳本很快就執行完並退出。在使用ps aux | grep sub命令搜索進程,應該可以在后台看到上述的兩個子腳本,說明成功掛起了子腳本。
在Web環境下,執行php腳本都是Web服務器開啟的cgi進程來處理,只要腳本不退出,就會一直占有該cgi進程,當啟動的所有cgi進程都被占用完后就不能在處理新的請求。所以對那些可能會很費時的腳本,可以采用異步的方式。啟動子腳本的方式和CLI差不多,必須要使用&和指定輸出(只好是定向到/dev/null),但是不能使用nohup。例如:
1 <?php 2 $cmd = 'php PATH_TO_SUB1/sub1.php >/dev/null &'; 3 exec($cmd); 4 $cmd = 'php PATH_TO_SUB1/sub2.php >/dev/null &'; 5 exec($cmd); 6 ?>
當在瀏覽器中訪問該腳本文件,可以看到瀏覽器里面響應完成,同時使用ps命令查看后台可以看到sub1和sub2腳本。
注意上述例子中如果php命令不在PATH中,需要指定命令完整的路徑。推薦使用完整路徑,特別是在Web下。
其他例子:
exec('phantomjs /var/www/joinfsite/api/library/Screenshots.js ' . $domain . ' /var/www/joinfsite/site/upload/kuaizhao/' . md5($domain) . '.jpg >/dev/null &');