當前位置: 首頁> 最新文章列表> curl_multi_close 在請求過程中出現中斷的應對方法

curl_multi_close 在請求過程中出現中斷的應對方法

gitbox 2025-05-29

在PHP 中使用curl_multi函數時,可能會遇到一個常見的情況:在多請求並行處理的過程中, curl_multi_close()被調用後,可能會中斷當前正在進行的請求。此問題有時會導致程序無法順利完成所有並發請求,因此需要採取適當的措施來避免這一問題。本文將介紹如何有效應對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()不會中斷請求,可以採用以下幾種方法:

1. 確保所有請求完成後再調用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()

2. 捕獲錯誤並進行重試

有時候,即使所有請求看似都已經完成,也可能由於網絡故障等問題出現中斷。這時,可以考慮在請求失敗時進行重試。

 <?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()函數會嘗試在請求失敗時進行重試,直到達到最大重試次數為止。這樣可以有效地避免由於網絡問題造成的請求中斷。

3. 使用curl_multi_select()

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 佔用。它是一個更高效的方式,尤其是在有大量請求時。