PHPcurl_multi_exec怎样并发调用服务_PHPcurl_multi_exec并发调用法【高效】

2次阅读

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

PHPcurl_multi_exec怎样并发调用服务_PHPcurl_multi_exec并发调用法【高效】

curl_multi_exec 为什么不能直接“并发”调用服务

curl_multi_exec 本身不发起并发请求,它只是轮询一批已 curl_setopt 配置好、且已 curl_multi_add_handle 加入句柄池的 cURL 资源。真正并发发生在底层 socket 层——前提是这些请求目标域名能被 DNS 快速解析、端口未被限流、且 php 没卡在阻塞操作上。

常见误操作是:在循环里反复 curl_initcurl_setoptcurl_exec,这本质是串行;而用 curl_multi_exec 却只调一次、不配合 curl_multi_select 或超时控制,结果多数请求卡在“等待响应”,看起来像没并发。

  • 必须提前把所有 CURLOPT_URLCURLOPT_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_handlecurl_close,否则内存泄漏

curl_multi_exec 返回值为 CURLM_OK 不代表全部完成

curl_multi_exec 返回 CURLM_OK 只表示“当前这一轮执行没有出错”,但 $active 参数才是真实进度——它返回当前仍在传输中的请求数。很多代码只检查返回值就去取结果,导致 curl_multi_getcontent 返回空或旧数据。

立即学习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_REUSECURLOPT_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 看各阶段耗时,比盲目调大并发数更有效。

text=ZqhQzanResources