enableCoroutine必须在Worker进程启动前调用,是一次性初始化动作;若在start()后、onWorkerStart之后或请求回调中调用则无效,且默认仅协程化PHP原生阻塞函数,第三方扩展需替换为协程版客户端。

enableCoroutine 必须在 Worker 进程启动前调用
它不是个随时可开关的开关,而是一次性初始化动作。一旦 Swoole 的 Worker 进程开始运行(比如 HttpServer->start() 或 Server->start() 执行后),再调用 Runtime::enableCoroutine() 就完全无效,也不会报错,但协程化不会生效。
常见错误是写在回调里、写在 onWorkerStart 之后、或者试图在 HTTP 请求处理函数中动态启用 —— 这些都晚了。
- 正确位置:
new HttpServer之后、->start()之前 - 如果用了
onWorkerStart,必须在该回调最开头就调用,且仅对当前 Worker 生效(但不推荐依赖这个) - CLI 模式下(如
swoole_http_server启动前)也适用同样规则
默认只协程化 PHP 原生函数,第三方扩展需手动标注
Runtime::enableCoroutine() 默认只拦截并协程化 PHP 标准库里的阻塞函数,比如 sleep()、file_get_contents()、curl_exec()(当使用 cURL handler 时)、mysqli_query()(需配合 mysqlnd 和 Swoole\Coroutine\MySQL)、stream_socket_client() 等。
但它对 PDO、Redis 扩展、Elasticsearch 客户端等第三方库无感知 —— 这些调用仍会阻塞整个协程。你得自己换用对应的协程版客户端,或用 Swoole\Coroutine\run() + go() 包裹异步逻辑。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- PDO 要换成
Swoole\Coroutine\MySQL或spiral/database等协程适配层 - Redis 推荐用
co\Redis(Swoole\Coroutine\Redis),而非phpredis -
file_get_contents("http://...")能协程化,但file_get_contents("/path/to/file")是同步 IO,不触发协程调度
开启后注意 MySQLi 和 PDO 的行为差异
MySQLi 在启用协程后,只要用的是 mysqlnd 驱动(PHP 7.4+ 默认),它的 query()、fetch() 等方法会自动变成协程安全;但 PDO 不会 —— 即使底层也是 mysqlnd,PDO 的所有操作仍是同步阻塞的。
这也是为什么很多项目踩坑:以为开了 enableCoroutine() 就万事大吉,结果 PDO 查询卡住整个协程,CPU 低但 QPS 上不去。
- 确认 MySQLi 是否协程化:执行
var_dump(MySQLi::getAvailableDrivers()),看到"mysqlnd"即可 - PDO 绝对不要直接用,必须改用
Swoole\Coroutine\MySQL或封装好的协程 ORM - 连接池要自己实现或借助
jetbrains/phpstorm-swoole插件提示,Swoole 不提供 PDO 连接池
调试时别忽略 Coroutine::stats() 和 strace
协程是否真在并发跑,光看代码逻辑不够。有时候看似启用了,实际因某处未协程化的阻塞调用(比如一个没换掉的 file_put_contents()),导致协程被挂起,表现和同步一样。
Coroutine::stats() 能告诉你当前有多少协程在运行、多少已结束、平均耗时,是第一手验证依据;而 strace -p $(pgrep php) 可以观察底层是否还在发 read()、write() 等系统调用 —— 如果频繁出现,说明仍有同步 IO 残留。
- 加一行
var_dump(Coroutine::stats());在请求末尾,对比高并发下的数字变化 - 用
co::sleep(0.001)主动让出调度权,避免单个协程长期霸占 CPU - 日志写入尽量用
Swoole\Coroutine\Channel+ 单独协程消费,别直接error_log()
go()。漏掉一个 file_get_contents 或误用 PDO,整条链路就退回同步模型。

















