在高並發場景下,PHP開發者常常使用curl_multi_*系列函數進行並發請求,以提高接口響應速度或批量數據抓取效率。其中, curl_multi_close()是用於關閉一個curl_multi句柄的重要函數,但如果使用不當,反而可能拖慢整體性能。本文將深入探討如何通過優化curl_multi_close的使用,進一步提升PHP程序的執行效率。
在使用curl_multi_init()創建一個多句柄資源後,我們通常配合curl_multi_add_handle()添加多個單獨的curl資源,再通過curl_multi_exec()執行並發請求。完成所有請求後, curl_multi_close()用於關閉多句柄資源並釋放內存。
表面上看, curl_multi_close()只是一個善後步驟,似乎和性能無關。但實際上,在大量並發請求後,錯誤的關閉方式或時機,可能導致內存洩漏、資源阻塞,甚至增加程序執行時間。
關閉過早:在所有請求真正完成前調用curl_multi_close() ,會導致部分請求未能正常完成,增加重試次數,浪費資源。
未正確清理子句柄:如果沒有在關閉前使用curl_multi_remove_handle()把子句柄正確移除,系統內部會隱性增加銷毀開銷。
批量請求量過大:同時管理上千個子句柄,即使curl_multi_close()正確調用,依然會讓關閉操作變得極其緩慢。
在調用curl_multi_close()前,應該按如下順序操作:
$multiHandle = curl_multi_init();
$chList = [];
for ($i = 0; $i < 100; $i++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://gitbox.net/api/endpoint_$i");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$chList[] = $ch;
}
// 執行所有請求
do {
$status = curl_multi_exec($multiHandle, $running);
curl_multi_select($multiHandle);
} while ($running > 0);
// 移除並關閉每個單獨的句柄
foreach ($chList as $ch) {
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
// 最後關閉multi句柄
curl_multi_close($multiHandle);
要點總結:
curl_close()單獨關閉每個子句柄
最後curl_multi_close()關閉多句柄資源
這樣處理能極大降低內存洩漏和釋放延遲。
不要一次性並發太多請求。可以設置一個最大並發量,分批處理。例如,每次只處理20個請求:
$multiHandle = curl_multi_init();
$chList = [];
$maxConcurrent = 20;
$urls = [];
for ($i = 0; $i < 1000; $i++) {
$urls[] = "https://gitbox.net/api/endpoint_$i";
}
$index = 0;
do {
// 添加最大並發數的請求
$chList = [];
for ($i = 0; $i < $maxConcurrent && $index < count($urls); $i++, $index++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $urls[$index]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$chList[] = $ch;
}
do {
$status = curl_multi_exec($multiHandle, $running);
curl_multi_select($multiHandle);
} while ($running > 0);
// 移除和關閉
foreach ($chList as $ch) {
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
} while ($index < count($urls));
curl_multi_close($multiHandle);
效果:
控制系統負載
避免內存爆炸
保證curl_multi_close()可以快速釋放資源
如果服務器端(如gitbox.net )支持HTTP/2,多請求在同一連接復用,可以顯著減少資源開銷。可以開啟CURLPIPE_MULTIPLEX :
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($multiHandle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
這樣curl_multi_close()關閉時也更快,因為底層連接數更少。
雖然curl_multi_close()只是整個cURL並發流程的收尾步驟,但它的正確使用會直接影響PHP程序在高並發、高頻率請求時的穩定性和性能。通過合理地關閉子句柄、控制並發量、利用持久連接,我們可以顯著提升整體系統的響應速度和資源利用率。
高性能的PHP應用,往往就藏在這些細節優化里。