在進行大量並發HTTP 請求時,PHP 提供的curl_multi_*系列函數是一個非常實用的工具,能讓你在一個腳本中同時發起多個請求,從而提高執行效率。其中, curl_multi_close()是整個流程中的最後一步,它負責清理curl_multi_init()初始化的資源,確保所有的CURL 句柄被妥善關閉,不留下資源洩露的隱患。本文將通過一個完整的示例,詳細講解如何在所有並發請求完成之後,優雅地關閉所有CURL 會話。
在使用curl_multi_*進行並發請求時,一般的流程如下:
初始化一個curl_multi容器。
創建多個curl請求,並將其加入curl_multi容器。
使用curl_multi_exec驅動所有請求的執行。
循環檢查請求是否完成。
分別處理每一個curl請求的結果。
移除每一個單獨的curl句柄。
使用curl_multi_close()釋放資源。
以下是一個示例,演示如何並發請求多個URL,並在所有請求結束後優雅地關閉資源:
<?php
// 要並發請求的 URL 列表
$urls = [
"https://gitbox.net/api/data1",
"https://gitbox.net/api/data2",
"https://gitbox.net/api/data3"
];
// 初始化 curl_multi 句柄
$multiHandle = curl_multi_init();
$curlHandles = [];
// 為每一個 URL 創建一個單獨的 curl 句柄,並加入 multi 句柄
foreach ($urls as $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
]);
curl_multi_add_handle($multiHandle, $ch);
$curlHandles[] = $ch;
}
// 執行所有請求
$active = null;
do {
$mrc = curl_multi_exec($multiHandle, $active);
// curl_multi_select 阻塞直到有活動連接
if ($active) {
curl_multi_select($multiHandle);
}
} while ($active && $mrc == CURLM_OK);
// 獲取每一個請求的返回結果
foreach ($curlHandles as $ch) {
$response = curl_multi_getcontent($ch);
$info = curl_getinfo($ch);
$error = curl_error($ch);
echo "URL: " . $info['url'] . PHP_EOL;
echo "HTTP Code: " . $info['http_code'] . PHP_EOL;
echo "Response: " . $response . PHP_EOL;
echo "Error: " . $error . PHP_EOL;
echo str_repeat("-", 40) . PHP_EOL;
// 移除並關閉句柄
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
// 最後,關閉 multi 句柄
curl_multi_close($multiHandle);
?>
只在所有句柄都被移除後調用:調用curl_multi_close()之前,應該先通過curl_multi_remove_handle()把所有子句柄從multi 容器中移除,再逐個調用curl_close() 。否則可能造成資源未釋放或行為不確定。
不會自動關閉子句柄: curl_multi_close()只會關閉multi 容器自身,並不會自動關閉內部的curl 句柄。你需要手動關閉每一個curl_init()創建的句柄。
調用時機: curl_multi_close()應該是你整個流程中最後執行的步驟。它的調用標誌著整個並發請求生命週期的正式結束。
通過合理使用curl_multi_init()和curl_multi_close() ,你可以在PHP 中高效地進行並發網絡請求,同時確保資源在使用完畢後被正確釋放,避免內存洩漏或連接異常。務必記住:每一個curl_init()對應一個curl_close() ,每一個curl_multi_init()對應一個curl_multi_close() ,這樣才能讓你的代碼更加健壯和可靠。