在高并发场景下,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应用,往往就藏在这些细节优化里。