php --ri swoole 输出必须含 coroutine => enabled,否则协程未编译启用;需结合 swoole_is_coroutine() 运行时验证、并发 sleep 测试及 SAPI 类型确认,避免静默降级。

php --ri swoole 输出里必须看到 coroutine => enabled
这是最直接的判断依据。运行 php --ri swoole,如果输出中没有 coroutine => enabled 这一行,说明协程根本没编译进去,后续所有 go()、co::sleep() 都会报错或静默降级为同步执行。
常见错误现象:
-
Call to undefined function go()—— 协程未启用,函数不可用 -
PHP Fatal error: Uncaught Error: Class 'Swoole\Coroutine' not found—— 扩展加载了,但没启协程支持 - 执行
go()后无任何输出,也不报错 —— 很可能被忽略而非真正调度
注意:有些旧版 Swoole(如 4.4.x 之前)即使启用了 --enable-coroutine,也可能不显示该字段,此时必须靠下一步验证。
用 swoole_is_coroutine() 实际检测上下文
光看模块信息不够,因为 CLI 和 Web 环境可能用不同 php.ini,且某些回调(如 onWorkerStart)默认不在协程环境里。唯一可靠的方式是运行时检测:
写一个测试脚本:
var_dump(swoole_is_coroutine()); // 应该是 false
go(function () {
var_dump(swoole_is_coroutine()); // 必须是 true
});
如果第二行输出不是 bool(true),说明协程调度器没工作。这时候要回退检查编译参数是否漏了 --enable-coroutine,或者 PHP 版本是否低于 7.4(Swoole 4.5+ 强制要求)。
容易踩的坑:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 在
onReceive或onRequest回调里直接调swoole_is_coroutine(),结果是false—— 这些回调本身不自动进入协程,得手动go()或用Co\run() - 用
php-fpm运行却只在 CLI 下测试成功 ——php-fpm的配置独立,extension=swoole.so必须出现在它的 php.ini 里
跑一个并发 sleep 测试,看是否真非阻塞
协程生效的最终表现是「多个耗时操作能并发执行而不互相等待」。下面这个例子能暴露绝大多数配置问题:
go(function () {
co::sleep(2);
echo "A\n";
});
go(function () {
co::sleep(1);
echo "B\n";
});
echo "C\n";
预期输出顺序是:C → B → A,总耗时约 2 秒。如果实际输出是 C → A → B,或总耗时接近 3 秒,说明协程没跑起来,co::sleep() 退化成了 sleep()。
性能影响很关键:这个测试在 CLI 下跑没问题,不代表 HTTP Server 也 OK。务必在真实服务里复现,比如用 Swoole\Http\Server 启一个端口,curl 并发请求两次,观察响应时间是否叠加。
扩展加载了但协程 API 不可用?查 PHP SAPI 类型
某些 SAPI(如 apache2handler)不支持 Swoole 协程,即使扩展加载成功,go() 也会直接失败。运行 php -v 看 SAPI 类型,确认是 cli 或 fpm;Apache 用户必须切到 php-fpm + nginx 模式。
另一个隐蔽点:php --ri swoole 显示版本是 5.0.3,但代码里用了 Swoole\Coroutine\Channel::pop()(5.1+ 才有),就会报 Call to undefined method。版本和 API 要严格对齐,不能只看大版本号。
复杂点往往藏在「你以为它在协程里,其实没进去」——比如在 Co\run() 外层调 go(),或在 onStart 里启动协程但忘了 Co\run() 包裹整个 Server 启动逻辑。这种问题不会报错,只会让协程静默失效。

















