當前位置: 首頁> 最新文章列表> 如何正確使用curl_multi_close 函數來結束長時間運行的請求?

如何正確使用curl_multi_close 函數來結束長時間運行的請求?

gitbox 2025-05-12

在PHP 中, curl_multi_*系列函數提供了一種強大的方式來同時發起多個HTTP 請求,從而提升程序的並發性能。其中, curl_multi_close()是一個用於清理資源的函數,它在所有並發請求完成後被調用,是釋放底層資源的重要步驟。但如果使用不當,可能會導致內存洩漏或請求未完全終止的問題。

本文將通過實際代碼示例,講解如何正確使用curl_multi_close()來結束長時間運行的請求。

一、什麼是curl_multi_close?

curl_multi_close()curl_multi_init()所配對的終結函數。它的作用是關閉一個多句柄資源(multi handle),並釋放與之相關聯的所有資源。注意,它並不會自動關閉添加到這個multi handle 的每一個單獨的curl handle,因此我們需要手動處理。

二、一個基本的並發請求示例

下面是一個使用curl_multi_*系列函數執行多個HTTP 請求並正確關閉資源的標準流程:

 <?php

// 創建要請求的 URL 數組
$urls = [
    'https://gitbox.net/api/endpoint1',
    'https://gitbox.net/api/endpoint2',
    'https://gitbox.net/api/endpoint3',
];

// 初始化 multi handle
$multiHandle = curl_multi_init();
$curlHandles = [];

// 為每個 URL 初始化單獨的 curl handle 並添加到 multi handle 中
foreach ($urls as $i => $url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($multiHandle, $ch);
    $curlHandles[$i] = $ch;
}

// 執行所有請求
$running = null;
do {
    $status = curl_multi_exec($multiHandle, $running);
    if ($running) {
        curl_multi_select($multiHandle); // 避免 CPU 佔用過高
    }
} while ($running && $status == CURLM_OK);

// 處理結果並關閉每個 curl handle
foreach ($curlHandles as $ch) {
    $response = curl_multi_getcontent($ch);
    $info = curl_getinfo($ch);
    echo "請求狀態碼: " . $info['http_code'] . "\n";
    echo "響應內容: " . substr($response, 0, 100) . "...\n"; // 只展示部分內容
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}

// 最後關閉 multi handle
curl_multi_close($multiHandle);

三、常見錯誤及解決方案

  1. 錯誤:沒有移除handle 就關閉multi handle

     // 錯誤用法
    curl_close($ch);  // 先關閉 curl handle
    curl_multi_close($mh);
    

    正確順序應該是:

     curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
    curl_multi_close($mh);
    
  2. 錯誤:未等待所有請求完成

    一些開發者會直接跳過curl_multi_select()或在curl_multi_exec()一次之後就直接關閉,導致部分請求未完成。使用do-while循環是一個可靠的方式,確保所有請求完成。

四、當請求耗時較長時該如何處理?

對於長時間運行的請求(如下載大文件或遠程計算),可以採用以下方式控制:

示例(加入超時控制):

 curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 設置最大執行時間為30秒

五、總結

curl_multi_close()本身並不復雜,但它必須與curl_multi_remove_handle()curl_close()配合使用,才能確保資源被徹底釋放。在高並發請求場景中,規範地關閉curl handle 是避免資源洩露和提升程序穩定性的關鍵。

使用多線程網絡請求時,謹記以下順序:

  1. 添加單個handle 到multi handle

  2. 執行multi handle

  3. 獲取結果

  4. 移除並關閉單個handle

  5. 最後關閉multi handle

通過上述方法,你可以高效地使用curl_multi_*系列函數,並正確地結束所有連接,提升代碼的可維護性和運行效率。