在PHP 中使用curl_multi函數時,可能會遇到一個常見的情況:在多請求並行處理的過程中, curl_multi_close()被調用後,可能會中斷當前正在進行的請求。此問題有時會導致程序無法順利完成所有並發請求,因此需要採取適當的措施來避免這一問題。本文將介紹如何有效應對curl_multi_close 在請求過程中出現中斷的問題。
curl_multi_close()是PHP 的cURL 擴展提供的一個函數,用於關閉通過curl_multi_init()創建的cURL 多重句柄。它的作用是釋放資源,但如果在請求過程中提前調用該函數,就有可能中斷尚未完成的請求。這樣可能導致數據丟失或請求不完全,從而影響系統的穩定性和性能。
以下是一個簡單的curl_multi請求示例:
<?php
// 初始化 curl_multi 句柄
$mh = curl_multi_init();
// 創建多個 cURL 句柄
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// 將每個 cURL 句柄添加到 multi 句柄中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 執行所有的請求
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 獲取返回數據
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 關閉 cURL 句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 關閉 multi 句柄
curl_multi_close($mh);
?>
在這個例子中,我們通過curl_multi_add_handle()將多個cURL 句柄添加到多重句柄$mh中,並通過curl_multi_exec()並行執行所有請求。最終,我們通過curl_multi_remove_handle()和curl_multi_close()關閉多重句柄。
問題出現在調用curl_multi_close()時,可能會提前關閉多重句柄,從而導致請求中途被中斷。若中斷發生在所有請求還未完成時,未完成的請求將無法獲取響應數據或返回結果。
為了確保curl_multi_close()不會中斷請求,可以採用以下幾種方法:
最常見的解決方法是確保所有請求都已完成後,再調用curl_multi_close() 。可以使用curl_multi_exec()的返回值來判斷是否所有請求都已完成。當running變量的值為0 時,表示所有請求已完成,這時才調用curl_multi_close() 。
修改後的代碼如下:
<?php
// 初始化 curl_multi 句柄
$mh = curl_multi_init();
// 創建多個 cURL 句柄
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// 將每個 cURL 句柄添加到 multi 句柄中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 執行所有的請求
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
// 可以在這裡添加一個小的延時以減緩 CPU 使用率
usleep(100);
} while ($running > 0);
// 獲取返回數據
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 關閉 cURL 句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 關閉 multi 句柄
curl_multi_close($mh);
?>
通過do-while循環持續執行請求,直到running為0,此時所有請求都已完成,可以安全地調用curl_multi_close() 。
有時候,即使所有請求看似都已經完成,也可能由於網絡故障等問題出現中斷。這時,可以考慮在請求失敗時進行重試。
<?php
// 設置最大重試次數
$maxRetries = 3;
function performRequest($ch, $maxRetries) {
$retryCount = 0;
$response = null;
while ($retryCount < $maxRetries) {
$response = curl_exec($ch);
if ($response !== false) {
break;
}
$retryCount++;
usleep(500000); // 等待一段時間後重試
}
return $response;
}
// 初始化 curl_multi 句柄
$mh = curl_multi_init();
// 創建多個 cURL 句柄
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// 將每個 cURL 句柄添加到 multi 句柄中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 執行所有的請求
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 獲取返回數據,進行重試
$response1 = performRequest($ch1, $maxRetries);
$response2 = performRequest($ch2, $maxRetries);
// 關閉 cURL 句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 關閉 multi 句柄
curl_multi_close($mh);
?>
在上述代碼中, performRequest()函數會嘗試在請求失敗時進行重試,直到達到最大重試次數為止。這樣可以有效地避免由於網絡問題造成的請求中斷。
curl_multi_select()可以幫助PHP 程序更高效地處理多個請求,避免在每次循環中都調用curl_multi_exec() 。它會在某些條件滿足時才會繼續執行請求,這樣可以節省系統資源。
<?php
// 初始化 curl_multi 句柄
$mh = curl_multi_init();
// 創建多個 cURL 句柄
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// 將每個 cURL 句柄添加到 multi 句柄中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 執行所有的請求
$running = null;
do {
curl_multi_select($mh);
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 獲取返回數據
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 關閉 cURL 句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 關閉 multi 句柄
curl_multi_close($mh);
?>
curl_multi_select()可以在沒有可用數據時進行等待,從而避免無謂的CPU 佔用。它是一個更高效的方式,尤其是在有大量請求時。