對於在短時間內需要重複執行某一簡單功能的系統而言,異步是優化性能的必經之路。
實現異步的方式有兩種:
1、模擬 HTTP 請求,這種方式每次都要經過三次握手,更適用於不同服務器之間的異步請求。
2、通過 CLI 與操作系統交互來實現。
一、模擬 HTTP 請求,每次執行的請求較慢,但因爲異步,性能也會有極大的優化。
HTTP協議維基百科:http://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE
模擬 HTTP 請求有兩種方式:CURL 與 SOCKET
CURL 實例如下:
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, 'http://www.ifeng.com');
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_BINARYTRANSFER, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
$content = curl_exec($handle);
var_dump($content);
CURL 可模擬所有的瀏覽器操作,也可進行加密傳輸。
socket 實例如下:
$host = 'www.ifeng.com';
$path = '/index.shtml';
$params = 'a=1&b=2&c=3';
$errorNo = null;
$errorMessage = '';
$timeOut = 30;
$fp = @fsockopen($host, 80, $errorNo, $errorMessage, $timeOut);
if(!$fp) {
exit('scoket 創建失敗:'.$errorMessage);
}
$request = '';
$request .= "POST ".$path." HTTP/1.1\r\n";
$request .= "Host: ".$host."\r\n";
$request .= "Connection: Close\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-length: ".strlen($params)."\r\n\r\n";
$request .= $params;
fputs($fp, $request);
$response = '';
while(!feof($fp)) {
$response .= fgets($fp, 128);
}
fclose($fp);
二、通過 CLI 在命令行與操作系統進行交互,此種方式只適用於請求自己系統的資源
通過 CLI 也有多種實現方式,大致分爲兩類:異步與多進程
異步與多進程在原理上是一致的,都是讓操作系統產生新的進程。
異步在於進程產生,執行完成後即消息,無法獲知進程的狀態。
多進程在於可以獲取進程執行的狀態,並控制殺死產生的子進程。
PHP沒有自帶的多進程處理機制,只能通過擴展來實現,如:pcntl 擴展
PHP 可以通過 exec,system,passthru,popen 等方式來實現。
PCNTL 實例如下:
$pid = pcntl_fork();
//echo $pid."<br/>";
if($pid == -1) {
exit('創建進程出錯');
} elseif($pid) {
exit('這裏是父進程');
} else {
//這裏可以不用異步
$phpShell = '/usr/local/php5.3/bin/php -f ';
$phpFile = 'process.php';
$processes = array();
for($i = 0; $i < 500; $i++) {
system($phpShell.$phpFile, $status);
$processes[$i] = $status;
echo $i."<br/>";
}
//exit('這裏是子進程');
}
process.php 代碼:
file_put_contents('/tmp/process.log', "start<br/>\r\n", FILE_APPEND);
PHP異步實例代碼:
//判斷OS
$isWin = false;
if(strpos(strtoupper(PHP_OS), 'WIN') !== false) {
$isWin = true;
}
//進程數量控制
if($isWin) {
$command = 'tasklist | find "php.exe" /c';
} else {
$command = "ps -ef | grep 'bin/php -f' | wc -l";
}
$count = 200;
$limit = 20;
$flag = true;
while($flag) {
if($count <= 0) {
break;
}
$handler = popen($command, 'r');
$number = fread($handler, 512);
echo $number."\r\n<br/>";
pclose($handler);
if($number > $limit) {
//sleep(1);
continue;
}
for($i = 0; $i < 20; $i++) {
$command = "/usr/local/php5.3/bin/php -f process.php >> /tmp/process.log &";
$handler = popen($command, 'r');
if(!$handler) {
echo "命令執行失敗\r\n";
//exit('命令執行失敗');
}
pclose($handler);
}
$count = $count - $limit;
}
exit;