當前位置: 首頁> 最新文章列表> curl_close 在大規模並發請求中的內存優化技巧

curl_close 在大規模並發請求中的內存優化技巧

gitbox 2025-05-18

在使用PHP 進行網絡請求時, curl是最常見的工具之一。尤其是在大規模並發場景中,比如批量拉取API 接口數據、推送通知、驗證多個地址等, curl往往是首選。而在這些實踐中,一個經常被討論的問題就是:

這聽起來像是個小細節,但在高並發場景下,這個細節可能會變成你程序能否穩定運行的關鍵。

1. 什麼是curl_close?

curl_close($ch)是PHP 的一個函數,用於關閉由curl_init()初始化的句柄$ch 。簡單來說,它會釋放掉相關的資源。許多教程和文檔會強調:“用完記得關”,聽起來似乎是個無需質疑的操作。

但是在大規模並發請求中,頻繁地開關資源,是否真的就意味著更高效?

2. 內存釋放≠ 內存回收

許多開發者誤以為只要調用了curl_close() ,內存就會立刻被“釋放”回系統,其實不然。在PHP 中,尤其是長連接腳本或者Swoole/FPM 常駐內存的情況下,PHP 的內存管理機制並不會立刻歸還內存給操作系統,而是將其標記為“可用”,等待下次使用。

這意味著,如果你的腳本中有成百上千次curl請求,即使你每次都調用了curl_close() ,內存佔用依然可能持續增長,尤其是在請求返回的數據體積較大時。

3. 實戰對比測試

下面通過一個簡單的對比測試來說明:

 // 場景一:未調用 curl_close
for ($i = 0; $i < 1000; $i++) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/test-endpoint?id=$i");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    // 忽略 curl_close
}

// 場景二:調用 curl_close
for ($i = 0; $i < 1000; $i++) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/test-endpoint?id=$i");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);
}

通過memory_get_usage()對比發現,在單次執行腳本中,兩種寫法在內存佔用上的差別並不大,甚至差別可以忽略不計。

但在FPM 處理多個請求Swoole 協程下長時間運行的服務中,未調用curl_close()會導致內存持續積壓,最終觸發OOM 或性能瓶頸。

4. 是否有更優的並發方式?

當並發請求數量很大時,使用curl_multi 才是正解。它允許你同時初始化並發的多個請求,通過輪詢機制異步處理返回,提高效率且更好地控制資源釋放。

 $multiHandle = curl_multi_init();
$curlHandles = [];

for ($i = 0; $i < 100; $i++) {
    $ch = curl_init("https://api.gitbox.net/batch?id=$i");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($multiHandle, $ch);
    $curlHandles[$i] = $ch;
}

// 執行並發請求
do {
    $status = curl_multi_exec($multiHandle, $active);
    curl_multi_select($multiHandle);
} while ($active);

// 獲取結果並關閉
foreach ($curlHandles as $ch) {
    $response = curl_multi_getcontent($ch);
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}

curl_multi_close($multiHandle);

5. curl_close 不能“救命”,但一定是“責任”

結論是: curl_close()本身並不能顯著優化內存,尤其在短生命週期的腳本中。但在高並發、常駐內存、長生命週期服務中,不調用curl_close()是嚴重的資源洩露,最終會拖垮你的服務穩定性。

所以,它不是性能優化的“秘訣”,但卻是你程序“能不能跑下去”的前提。

小建議

  • 普通批處理腳本:推薦使用curl + curl_close

  • 高並發處理:使用curl_multi 或使用協程客戶端(如Guzzle + async)

  • 長連接服務:務必管理資源生命週期,包括curl_close

  • PHP FPM:注意腳本中請求的內存佔用,合理拆分請求或控制請求體積

在細節面前,性能才會穩如磐石。下次你再寫並發請求時,不妨回頭看看,你是不是忘了curl_close()