curl_exec在workerman中绝对不能用,因其是同步阻塞调用,会卡住事件循环,导致整个worker进程无法处理其他连接;必须改用workerman\http\client等异步客户端或子进程隔离。

直接用 curl_exec 会阻塞整个 Workerman 进程,导致其他连接无法处理——这不是并发低,是根本没在异步运行。
为什么 curl_exec 在 Workerman 里绝对不能用
Workerman 基于事件循环,所有 I/O 操作必须是非阻塞的。curl_exec 是同步阻塞调用,一旦发起,当前 worker 进程就卡住,直到响应返回或超时。哪怕只用一次,也会让该 worker 在此期间拒绝所有新请求。
- 常见错误现象:
onMessage回调里调了curl_exec,结果并发一上来,连接堆积、响应延迟飙升,netstat显示大量TIME_WAIT或连接排队 - 性能影响:1 个阻塞请求就能拖垮整个 worker,
Worker::$maxConnection再大也没用 - 兼容性陷阱:有人试图用
CURLOPT_NOSIGNAL或curl_multi补救,但 multi 在 PHP-FPM 下可用,在 Workerman 的 eventloop 里依然不兼容,容易触发 segfault 或资源泄漏
改用 Workerman\Http\Client 替代 curl_exec
这是官方推荐、开箱即用的异步 HTTP 客户端,内置连接池、自动复用 TCP 连接、符合 PSR-7,且不依赖扩展(纯 PHP 实现)。
基于5000余部现行法律法规进行的高质量专业合同审查,一键输出审查意见书,并附有参考法条原文,满足专业溯源核查要求。由accurLex知法提供技术支持。 Use when users ask for 合同审查, 审查意见书, 合同风险分析, 条款审查,知法,accurLex or 站在甲方/乙方角度审查合同 through accurLex direct API. China law only, plaintext only, review mode limited to 审查意见书.
- 安装:
composer require workerman/http-client - 基本用法:在
onWorkerStart或onMessage中创建实例,调用get/post,传入 success/error 回调,不是返回值 - 注意点:
$http实例可复用,但不要跨 worker 共享;每个请求的回调函数必须能处理异常(比如 DNS 失败、连接被拒、超时) - 超时必须显式设置:默认无超时,得用
setTimeout(3)控制最大等待时间,否则照样卡住 eventloop
$http = new Workerman\Http\Client();
$http->setTimeout(3); // 必须设
$http->get('https://api.example.com/data', function ($response) {
echo $response->getBody();
}, function ($exception) {
echo 'Request failed: ' . $exception->getMessage();
});
遇到需要自定义协议或非 HTTP 场景怎么办
比如要连 Redis、MySQL、或私有 TCP 服务,Workerman\Http\Client 不适用,得回到 AsyncTcpConnection,但必须手动处理协议边界和错误。
- 别直接 new 后就 send:构造函数不触发连接,得监听
onConnect才算真正连上 - 必须设
onError:DNS 解析失败、连接被拒、远端关闭等错误不会抛异常,不监听就静默失败 - 发完数据不能假设立刻收到响应:TCP 是流式协议,需自己缓冲拼包(如按 \n 分隔),不能把每次
onMessage的$data当完整响应 - 连接空闲后远端可能已断开:得加心跳或重连逻辑,否则下次 send 会失败
如果业务逻辑实在绕不开同步 cURL(比如遗留 SDK)
唯一安全做法是把同步操作剥离到子进程,用 pcntl_fork + proc_open 或更稳妥的 Workerman\Process,但代价高、管理复杂,仅作兜底。
- 子进程崩溃不影响主 worker,但需手动回收
pcntl_waitpid,否则变僵尸进程 - 父子进程通信靠 pipe 或临时文件,有额外序列化/IO 开销,QPS 显著下降
- Windows 下
pcntl不可用,此方案直接失效 - 更现实的选择:重构调用方,或找对应异步 SDK(如
amphp/mysql、phpredis的异步分支)
真正的难点不在“怎么换”,而在识别哪些地方悄悄用了同步调用——比如日志里的 file_put_contents、配置加载里的 file_get_contents、甚至某些 ORM 的懒加载,都可能成为隐藏的阻塞点。










