应复用同一guzzlehttp\client实例并发请求,通过getasync()发起异步调用、promise::all()聚合、wait()触发执行,并配置tcp保活、分设超时、用retry中间件处理错误。

并发发请求时别直接 new Client() 多次
每次 new GuzzleHttp\Client() 都会新建一个独立的 cURL 句柄池和连接管理器,既浪费资源又无法复用 TCP 连接,反而拖慢并发性能。真正该做的是复用同一个 Client 实例,再配合 Promise 异步发请求。
- 必须设置
curl级连接复用:在 Client 构造时传入['curl' => [CURLOPT_TCP_KEEPALIVE => 1]] - 推荐显式配置
http_errors => false,否则 4xx/5xx 会直接抛异常,打断 Promise.all 的执行流 - 避免在循环里写
$client->get($url)—— 这是同步阻塞调用,根本没并发
用 Promise\all() 聚合多个异步请求
GuzzleHttp\Promise\Promise 不是“多线程”,而是基于事件循环的非阻塞 I/O 调度。它依赖 PHP 的 curl_multi(默认启用)或 ev/libevent 扩展(需手动装),底层仍是单线程异步。
- 每个请求要用
$client->getAsync($url)或$client->requestAsync('GET', $url),返回Promise对象 - 把所有 Promise 收集进数组,再用
Promise\all($promises)触发并发;不要用Promise\settle()除非你明确要区分成功/失败 - 记得调用
$promise->wait()启动执行 —— 没这句,什么都不会发出去
$promises = [];
foreach ($urls as $url) {
$promises[] = $client->getAsync($url);
}
$responses = Promise\all($promises)->wait(); // 注意这里必须 wait()
超时、重试、错误处理不能只靠 try/catch 包一层
Promise 并发下,单个请求失败不会中断整个 Promise\all(),但默认会把异常包进 Rejection,直接 wait() 会 throw。常见错误是只在外层 try/catch,结果一两个失败就崩了整个批次。
- 对每个 Promise 单独加
otherwise()处理失败:如$p->otherwise(fn($e) => ['error' => $e->getMessage()]) - 连接级超时用
connect_timeout(单位秒),读取超时用timeout,两者必须分开设,否则容易误判 - 重试逻辑建议用
GuzzleHttp\Middleware::retry(),别手写 while 循环 —— 它能自动识别网络抖动类错误(如ConnectException)
实际跑不起来?先检查这三件事
很多“并发没效果”问题其实跟 Guzzle 无关,而是环境或配置卡住。
- 确认 PHP 是 CLI 模式运行(
php -S或命令行),Web SAPI(如 Apache mod_php)对 curl_multi 支持差,容易假死 - 检查
curl_setopt_array()是否被禁用(某些共享主机会关),否则Client初始化就失败 - 别在
foreach里直接echo $response->getBody()——wait()前 body 是空的,必须等 Promise 解析完才能读
并发数不是越多越好,超过服务端连接限制或本地文件描述符上限(ulimit -n)反而导致大量 cURL error 7 或 Connection refused。真要压测,得配合连接池和限流做。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











