在PHP 中, curl_multi_*系列函數提供了一種強大的方式來同時發起多個HTTP 請求,從而提升程序的並發性能。其中, 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);
錯誤:沒有移除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);
錯誤:未等待所有請求完成
一些開發者會直接跳過curl_multi_select()或在curl_multi_exec()一次之後就直接關閉,導致部分請求未完成。使用do-while循環是一個可靠的方式,確保所有請求完成。
對於長時間運行的請求(如下載大文件或遠程計算),可以採用以下方式控制:
設置合理的CURLOPT_TIMEOUT
使用curl_multi_select()減少CPU 佔用
檢查並處理curl_multi_info_read()返回的狀態
示例(加入超時控制):
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 設置最大執行時間為30秒
curl_multi_close()本身並不復雜,但它必須與curl_multi_remove_handle()和curl_close()配合使用,才能確保資源被徹底釋放。在高並發請求場景中,規範地關閉curl handle 是避免資源洩露和提升程序穩定性的關鍵。
使用多線程網絡請求時,謹記以下順序:
添加單個handle 到multi handle
執行multi handle
獲取結果
移除並關閉單個handle
最後關閉multi handle
通過上述方法,你可以高效地使用curl_multi_*系列函數,並正確地結束所有連接,提升代碼的可維護性和運行效率。