串接多個後端 API 時,循序請求會導致總耗時等於所有 API 耗時之和。使用 curl_multi 並發請求,可將總耗時降至最慢單一 API 的耗時,顯著提升頁面載入速度。
<?php
function curl_fetch($url, $timeout = 3) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_RETURNTRANSFER => 1,
]);
$data = curl_exec($ch);
$errno = curl_errno($ch);
curl_close($ch);
return $errno ? false : $data;
}
$urls = [
"taobao" => "https://www.taobao.com",
"sohu" => "https://www.sohu.com",
"sina" => "https://www.sina.com.cn",
];
$start = microtime(true);
$results = [];
foreach ($urls as $key => $url) {
$results[$key] = curl_fetch($url);
}
echo "循序耗時: " . (microtime(true) - $start) . " 秒"; // 約 0.614 秒
?>
<?php
function curl_multi_fetch(array $urls, $timeout = 2): array {
$mh = curl_multi_init();
$handles = [];
$results = [];
// 初始化所有 handle 並加入 multi handle
foreach ($urls as $key => $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
]);
curl_multi_add_handle($mh, $ch);
$handles[$key] = $ch;
}
// 執行並發請求
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($mrc === CURLM_CALL_MULTI_PERFORM);
while ($running && $mrc === CURLM_OK) {
// 等待網路活動
if (curl_multi_select($mh, 0.5) > -1) {
do {
$mrc = curl_multi_exec($mh, $running);
} while ($mrc === CURLM_CALL_MULTI_PERFORM);
}
}
// 收集結果
foreach ($handles as $key => $ch) {
if (curl_errno($ch) === 0) {
$results[$key] = curl_multi_getcontent($ch);
} else {
$results[$key] = false;
error_log("cURL error ({$key}): " . curl_error($ch));
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
$start = microtime(true);
$results = curl_multi_fetch($urls);
echo "並發耗時: " . (microtime(true) - $start) . " 秒"; // 約 0.316 秒
?>
| 函數 | 用途 |
|---|---|
curl_multi_init() | 建立多執行緒控制代碼 |
curl_multi_add_handle() | 加入單一 cURL handle |
curl_multi_exec() | 執行並發請求 |
curl_multi_select() | 等待任一連線有活動(可設超時) |
curl_multi_getcontent() | 取得已完成請求的回應內容 |
curl_multi_info_read() | 讀取已完成傳輸的詳細資訊 |
curl_multi_remove_handle() | 移除 handle |
curl_multi_close() | 關閉多執行緒控制代碼 |
CURLOPT_TIMEOUT 避免單一慢速 API 拖垮整體curl_errno() 區分網路錯誤與 HTTP 錯誤碼CURLOPT_TCP_KEEPALIVE 減少握手開銷測試環境下,3 個 API 並發請求將總耗時從 0.614 秒降至 0.316 秒,效能提升約 48%。實際提升幅度取決於最慢 API 的回應時間與網路延遲。