curl_multi_exec 本身不并发,仅轮询已配置的curl句柄;真并发依赖底层socket就绪、dns快速解析及无阻塞操作,需配合curl_multi_select与$active状态循环控制。

curl_multi_exec 为什么不能直接“并发”调用服务
curl_multi_exec 本身不发起并发请求,它只是轮询一批已 curl_setopt 配置好、且已 curl_multi_add_handle 加入句柄池的 cURL 资源。真正并发发生在底层 socket 层——前提是这些请求目标域名能被 DNS 快速解析、端口未被限流、且 PHP 没卡在阻塞操作上。
常见误操作是:在循环里反复 curl_init → curl_setopt → curl_exec,这本质是串行;而用 curl_multi_exec 却只调一次、不配合 curl_multi_select 或超时控制,结果多数请求卡在“等待响应”,看起来像没并发。
- 必须提前把所有
CURLOPT_URL、CURLOPT_RETURNTRANSFER等设好,再统一加入 multi 句柄 - 不能在
curl_multi_exec后立刻读响应——得等curl_multi_info_read返回完成状态 - DNS 解析慢会拖垮整组请求,建议开启
CURLOPT_DNS_CACHE_TIMEOUT或预解析
标准 while 循环 + curl\_multi\_select 的写法
这是最稳妥的并发控制模式,避免 CPU 空转,也防止某请求 hang 死整个流程。
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
curl_multi_add_handle($mh, $ch);
$handles[] = $ch;
}
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
if ($mrc == CURLM_CALL_MULTI_PERFORM) continue;
if ($active > 0) {
curl_multi_select($mh, 1); // 最多等 1 秒
}
} while ($active > 0 && $mrc == CURLM_OK);
// 读取结果
foreach ($handles as $ch) {
$result = curl_multi_getcontent($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 处理 $result 和 $httpCode
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
-
curl_multi_select是关键:它让 PHP 等待任意一个 socket 就绪,而不是忙等 -
CURLOPT_TIMEOUT_MS推荐设为毫秒级,避免单个慢请求拖累全局 - 别漏掉
curl_multi_remove_handle和curl_close,否则内存泄漏
curl\_multi\_exec 返回值为 CURLM\_OK 不代表全部完成
curl_multi_exec 返回 CURLM_OK 只表示“当前这一轮执行没有出错”,但 $active 参数才是真实进度——它返回当前仍在传输中的请求数。很多代码只检查返回值就去取结果,导致 curl_multi_getcontent 返回空或旧数据。
启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。
立即学习“PHP免费学习笔记(深入)”;
- 务必以
$active === 0作为循环退出条件,不是靠返回值 - 即使
$active > 0,也要用curl_multi_info_read主动捞已完成的句柄,避免死等 - 若需部分失败后继续,可在
curl_multi_info_read中判断CURLINFO_RESULT是否为CURLE_OK
并发数限制与连接复用的影响
PHP 默认对同一 host 最多保持 2 个 HTTP/1.1 连接(受 curl 底层限制),大量请求打向同一个域名时,后发请求会排队等待空闲连接,实际并发度远低于句柄数。
- 启用
CURLOPT_FORBID_REUSE或CURLOPT_FRESH_CONNECT会彻底禁用复用,更耗资源 - HTTP/2 支持可提升单连接并发能力,但需 PHP ≥ 7.2 + cURL ≥ 7.47.0 + OpenSSL 支持 ALPN
- 如目标服务支持,可考虑按域名分批调度,或改用
curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 20)(注意 libcurl 版本)
真正卡点往往不在 PHP 侧,而在 DNS、TLS 握手、服务端限流或对方 Keep-Alive 策略。压测前先用 curl -w "@format.txt" -o /dev/null -s http://x 看各阶段耗时,比盲目调大并发数更有效。










