在PHP 中, curl_multi_*系列函數可以讓你並發發送多個HTTP 請求,大大提高了程序的執行效率。不過,很多人在使用curl_multi_close結束多請求會話時,容易忽略一個重要問題:。
如果沒有合理控制超時時間,當某個請求長時間無響應時,整個應用可能被卡住,造成非常糟糕的用戶體驗。本文將通過示例,教你如何在使用curl_multi_close時,優雅地實現超時控制。
其實, curl_multi_close只是用來關閉curl_multi句柄的,它本身不控制超時。真正的超時控制應該發生在執行請求(即curl_multi_exec和curl_multi_select )的階段。
簡單說,超時控制靠的是:
在單個curl 句柄上設置timeout
在執行循環中自行記錄和判斷總耗時
下面是一個實際的示例。假設我們有兩個請求,分別請求https://gitbox.net/api/endpoint1和https://gitbox.net/api/endpoint2 ,我們希望所有請求總耗時不能超過10 秒。
<?php
// 創建兩個 cURL 句柄
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');
// 給每個請求單獨設置超時(可選)
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_TIMEOUT, 8); // 單個請求最多8秒
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_TIMEOUT, 8);
// 創建一個 cURL 批處理句柄
$mh = curl_multi_init();
// 添加句柄到批處理句柄中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 執行批處理
$startTime = microtime(true);
$timeout = 10; // 總超時時間(秒)
do {
$status = curl_multi_exec($mh, $active);
// 如果還有活動的連接
if ($active) {
// 阻塞等待
$n = curl_multi_select($mh, 1.0);
// 如果 select 返回 -1,避免忙等
if ($n === -1) {
usleep(100000); // 睡100毫秒
}
}
// 檢查是否超時
if ((microtime(true) - $startTime) > $timeout) {
echo "請求總耗時超過{$timeout}秒,強制中斷。\n";
break;
}
} while ($active && $status == CURLM_OK);
// 讀取結果
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 關閉句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
curl_close($ch1);
curl_close($ch2);
// 打印結果
echo "Response 1: " . substr($response1, 0, 100) . "...\n";
echo "Response 2: " . substr($response2, 0, 100) . "...\n";
?>
CURLOPT_TIMEOUT控制單個請求的超時;
通過記錄microtime(true) ,手動控制總執行時間;
使用curl_multi_select時要設定適當的超時值(比如1 秒),避免CPU 佔用過高;
curl_multi_close只負責清理資源,不會控制任何超時邏輯。
如果你設置了過短的select 超時時間(例如0.01秒),系統負載可能升高。
如果curl_multi_select返回-1,意味著沒有文件描述符可以等待,需要適當睡眠( usleep ) 避免忙循環。
當超時發生時,最好能主動取消未完成的請求,以避免資源洩漏。