Workerman协程启用需分阶段平滑切换:先验证环境支持(swoole/swow/fiber),升级至5.0+,顶部初始化revolt/event-loop,设worker count为1,替换阻塞调用为协程安全版本,并通过Coroutine::id()、内存占用及ab压测验证效果。

你需要在现有Workerman多进程项目中启用协程能力,又不想重写业务逻辑、不中断线上服务、不引发连接丢失或请求堆积——平滑切换的核心是分阶段替换事件循环与运行时,而非一次性推倒重来。
确认当前环境是否支持协程
执行 php -m | grep -E 'swoole|swow|fiber' 查看是否有协程扩展可用。若无任何输出,说明当前纯PHP环境,只能走Workerman 5.0原生Fiber路线;若有Swoole或Swow,则可选其驱动,性能更优。
【必须提前验证】 如果项目已使用 pcntl_fork() 或手动 posix_kill() 等进程控制函数,协程模式下这些调用将直接失败并抛出致命错误,需先剥离。
逐步启用Workerman 5.0协程运行时
第一步:升级到Workerman 5.0+,执行 composer update workerman/workerman:^5.0。旧版Workerman(4.x)无法加载revolt/event-loop,强行启用会报 Class "Revolt\EventLoop" not found。
第二步:在启动脚本顶部加入协程初始化代码,位置必须在 Worker::runAll() 之前:
use Revolt\EventLoop; EventLoop::setExceptionHandler(fn($e) => error_log($e));
第三步:禁用传统多进程调度,将 $worker->count = 4; 改为 $worker->count = 1;。协程模型下,单进程即可承载数千并发,多进程反而造成资源争抢和状态隔离困难。
第四步:在 onMessage 回调内,把所有阻塞调用替换为协程安全版本——file_get_contents → Workerman\Http\Client,mysqli_query → Workerman\Mysql\Connection,否则协程会被卡死,整个事件循环停滞。
保留多进程结构,仅协程化关键路径
方法一:混合部署——主Worker仍用多进程,但将耗时I/O密集型子任务(如第三方API调用、日志上报、异步通知)单独抽离为协程任务。
在 onMessage 中调用:Coroutine::create(fn() => $this->doAsyncJob($data));,该协程由当前Worker进程内的事件循环调度,不影响其他连接处理。
方法二:双轨制启动——用两个独立Worker实例:一个保持传统多进程模式处理登录、鉴权等CPU敏感逻辑;另一个启用协程模式专跑支付回调、消息推送等I/O密集链路。两者通过Redis Pub/Sub通信,完全解耦。
注意:不要在协程Worker里调用 sleep(1),它会挂起整个进程;必须改用 await Sleep::usleep(1000000) 或 EventLoop::delay(1.0, fn() => {...})。
验证协程是否真正生效
在任意协程回调中插入一行:var_dump(Coroutine::id());。若每次请求输出不同数字(如 1、2、3…),说明协程已调度;若始终为 0 或报错 Call to undefined function Coroutine::id(),说明协程未启用成功。
观察内存占用:传统4进程模式下,每个Worker常驻内存约15–20MB;切换为单进程协程后,总内存应降至8–12MB左右。超出该范围,大概率存在协程泄漏或未正确关闭连接。
用 ab -n 1000 -c 200 http://localhost:8000/test 压测,对比QPS变化。协程生效后,相同硬件下QPS应提升3–5倍,且错误率趋近于0。若出现大量 Connection refused 或超时,说明事件循环被阻塞,需检查是否有遗留的同步IO调用。

















