通用的非同步執行檔案 exec.php
sleep(8);
$data = "--- type " . date("Y-m-d H:i:s") . " ---\\n";
file_put_contents("../log.txt", $data, FILE_APPEND);
popen
通過 popen() 函式開啟程式檔案指標,從而能非同步執行指令碼檔案。(只在linux下有效)
pclose(popen("php exec.php &", 'r'));
echo 1;
缺點:只能非同步執行本地的指令碼檔案,不能跨域執行,不能傳遞引數。
每次執行都會建立新的程式,當併發量高時就建立大量程式,從而造成資源浪費。
curl
應用程式以 curl 發起 http 請求的形式實現非同步。但是 curl 請求也需要等待請求返回,程式同樣會阻塞,這時我們需要設定 http 請求的超時時間為1s,這樣相當於發起了一個 http 請求去執行任務,但是不等待其返回結果,繼續向下執行程式,這樣就可以實現非同步效果。
function asyncCurl($url, $data)
{
if (is_array($data)) {
$data = http_build_query($data, null, '&');
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result['response'] = curl_exec($ch);
$result['httpCode'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
return $result;
}
$url = "<http://127.0.0.1/exec.php>";
$data = [];
asyncCurl($url, $data);
echo "OK";
curl 請求實現非同步方式的缺陷就是 http 請求的最小超時時間為1s。也就是應用程式無論如何都要等待1s鍾以上才能響應(現在 curl 擴充套件也能支援毫秒級別的超時時間設定,不過毫秒時間的超時很容易造成請求失敗)。
fsockopen
fsockopen() 函式用於開啟一個網路連線或者一個Unix套接字連線。通過發起 http 通訊來實現非同步。
從原理上來說與 curl 請求一樣。
function sockPost($host, $url, $param)
{
$port = parse_url($url, PHP_URL_PORT);
$port = $port ? $port : 80;
$scheme = parse_url($url, PHP_URL_SCHEME);
$path = parse_url($url, PHP_URL_PATH);
$query = http_build_query($param);
if ($scheme == 'https') {
$host = 'ssl://' . $host;
}
$fp = fsockopen($host, $port, $error_code, $error_msg, 1);
if (!$fp) {
return array('error_code' => $error_code, 'error_msg' => $error_msg);
} else {
stream_set_blocking($fp, 0);
stream_set_timeout($fp, 10);
$header = "GET $path" . "?" . "$query" . " HTTP/1.1\\r\\n";
$header .= "Host: $host\\r\\n";
$header .= "Connection: close\\r\\n\\r\\n";//長連線關閉
fwrite($fp, $header);
usleep(2000); // 延時,防止在nginx伺服器上無法執行成功
fclose($fp);
return array('error_code' => 0);
}
}
$host = "127.0.0.1";
$url = "/exec.php";
$param = [];
$result = sockPost($host, $url, $param);
var_dump($result);
fsockopen 方式相比 curl 更復雜,需要自己拼接處 http 請求的 header 部分。在 curl 不支援毫秒級超時之前 fsockopen 方式無疑是最佳選擇。
本作品採用《CC 協議》,轉載必須註明作者和本文連結