必须在所有协程代码执行前且仅调用一次,置于webman的start.php/server.php或swoole server实例化前;不可在go()内、路由回调或onworkerstart中调用;推荐显式指定最小hook标志而非swoole_hook_all。

必须放在所有协程代码执行前,且只能调用一次(重复调用无效果,也不会报错)。
放在 Webman 或 Swoole Server 的启动入口最顶端
比如 Webman 项目中,在 start.php 或 server.php 文件开头、Swoole\Server 实例化之前就启用:
<?php Swoole\Runtime::enableCoroutine(); // 后续所有 go()、协程客户端、协程文件操作才真正非阻塞
- 如果放在
go()内部或某个路由回调里,对当前协程无效——Hook 是进程级全局设置,不是协程局部开关 - Webman 默认已在
server.php中调用了,自行添加前先确认是否已存在,避免冗余 - 在 CLI 脚本中也一样:必须在第一个
go()之前,否则fopen、file_get_contents等仍会阻塞主线程
不能放在 Swoole Server 的 onWorkerStart 回调里
看似“每个 worker 启动时都启用”很稳妥,但实际会导致不可预期行为:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
-
onWorkerStart是多线程环境(worker 进程可能被多线程复用),而Swoole\Runtime::enableCoroutine()是进程级单次生效的,重复调用不改变状态 - 更严重的是:如果某些 worker 先执行了
onWorkerStart并启用 Hook,而其他 worker 尚未执行,此时跨 worker 的协程调度可能因 Hook 状态不一致出问题 - 官方明确建议只在主进程启动初期调用,而非运行时动态切换
慎用 SWOOLE_HOOK_ALL 和细粒度 flag 组合
默认 Swoole\Runtime::enableCoroutine() 等价于 Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL),但并非所有函数都适合全量 Hook:
-
SWOOLE_HOOK_CURL会接管curl_exec,但如果你项目里混用了 Guzzle(底层是 cURL)和Swoole\Coroutine\Http\Client,可能引发冲突或超时异常 -
SWOOLE_HOOK_FILE会让fopen/file_get_contents变成协程友好,但某些依赖同步文件锁(flock)的逻辑会失效——协程切换时锁可能被意外释放 - 生产环境建议显式指定最小必要 flag,例如:
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_TCP | SWOOLE_HOOK_SLEEP)
最容易被忽略的一点:启用后,所有后续 PHP 标准 I/O 函数的行为都会变,但错误提示不会告诉你“这是协程 Hook 导致的”。比如 fopen 失败时抛出的异常类型、超时机制、甚至 errno 值,都和原生不同。调试时得盯着 Swoole\Coroutine\System::gethostbyname 这类协程原生替代方案,而不是硬扛被 Hook 改写的函数。










