协程不可用的主因是Swoole未启用协程支持或PHP未进入协程环境;php --ri swoole无"Coroutine => enabled"字样即说明协程未开启,需检查编译参数、php.ini配置及Runtime::enableCoroutine调用时机。

协程功能用不了,大概率不是代码写错了,而是 Swoole 扩展没真正启用协程支持,或者 PHP 运行时没进入协程环境。
php --ri swoole 输出里没有 "Coroutine" 字样
这是最直接的判断依据。只要 php --ri swoole 的输出中不出现 Coroutine => enabled 或类似字段,协程 API(比如 Swoole\Coroutine::sleep()、go())就根本不可用。
- 如果输出里只有
Version和enabled,但没提Coroutine,说明编译时没开协程开关——Swoole 5.x 默认开启,但 4.x 必须手动加--enable-coroutine - 宝塔或源码编译安装时,漏掉
--enable-coroutine参数是常见原因;PECL 安装一般默认带,但旧版 PECL 可能不带 - 执行
/www/server/php/82/bin/php --ri swoole(路径按你实际 PHP 版本调整),别只信php -m | grep swoole,它只管模块名,不管功能开关
phpinfo() 页面里 swoole 扩展显示正常,但 go() 报错 “Call to undefined function”
这说明扩展加载了,但协程函数没暴露出来,通常是 CLI 和 FPM 的 php.ini 没同步改全,或者扩展加载顺序冲突。
- 宝塔用户必须同时编辑两个文件:
/www/server/php/82/etc/php.ini(CLI)和/www/server/php/82/etc/php-fpm.d/www.conf里的php_admin_value[extension]行(FPM),都加extension=swoole.so(新版可能为extension=swoole,无 .so) - 别只改一个:改了 CLI 的 php.ini,
php --ri swoole看起来正常;但 Web 请求走 FPM,没加载扩展,go()就直接报函数未定义 - 检查
extension_dir是否指向正确路径,尤其 Windows 下容易配错extension_dir = "ext"却没把php_swoole.dll放进去
协程函数能调,但 file_get_contents()、curl_exec() 这些原生函数还是阻塞
PHP 8.2 默认不自动 Hook 原生函数,协程环境里它们仍走同步 IO,导致协程“假并发”。
立即学习“PHP免费学习笔记(深入)”;
- 必须显式启用协程 Hook:
Swoole\Runtime::enableCoroutine(true),且要在任何协程启动前(比如go()之前)调用 - 这个调用不能放在
go()里面,也不能在类构造函数里——得在脚本最顶部、go()之前执行 - 注意:
enableCoroutine()对已运行的协程无效,只影响后续创建的协程;若用了框架(如 Hyperf、ThinkSwoole),确认框架是否已帮你调了,否则要自己补 - 某些场景下需指定 Hook 范围,例如只 Hook MySQL:
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL)或更细粒度的常量
go() 执行了,但协程内 sleep() 不生效或直接退出
这不是扩展问题,而是运行环境没进协程上下文——常见于在非协程函数里直接调用协程 API。
-
Swoole\Coroutine::sleep()只能在协程内调用,否则会报must be called in the coroutine - 确保你在
go()回调里、或Swoole\Http\Server的on('Request')回调里用它;不要在普通函数、命令行脚本顶层直接调 - 如果用的是 ThinkPHP + think-swoole,数据库查询卡住,往往是因为 PDO 驱动没换,不是协程 sleep 失效——那是另一个问题,得切到
Swoole\Coroutine\MySQL - 调试时加
var_dump(Swoole\Coroutine::getCid());,返回 0 说明不在协程里,返回正整数才是真协程
真正容易被忽略的是:Swoole 5.x 在 PHP 8.2 下虽支持协程,但 enableCoroutine() 默认不开启原生函数 Hook,且 CLI/FPM 配置分离极易漏改一个。别急着重装扩展,先跑一遍 php --ri swoole 和 var_dump(Swoole\Coroutine::getCid()),比猜更准。



















