要让Swoole 4.x真正跑起协程,必须闭环三步:启用协程Hook、在支持上下文(如onRequest)中调用协程客户端、避免混用同步阻塞函数;缺一不可,否则仍为串行阻塞。

要让 Swoole 4.x 真正跑起协程,关键不是“装了扩展就行”,而是三步必须闭环:启用协程 Hook、在支持上下文中调用协程客户端、避免混用同步阻塞函数。缺一不可,否则看似写了协程代码,实际仍是串行阻塞。
启用协程的两个必要动作
Swoole 协程不是默认开启的,需主动激活:
-
全局 Hook(推荐):在服务启动入口(如 Webman 的 start.php 或 Swoole Server 启动前)调用
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL)。它会自动将常见 I/O 函数(如file_get_contents、curl_exec、mysql_connect等)重写为协程安全版本。 -
手动创建协程:在不支持协程的回调(如
onWorkerStop)中,可用go(function () { ... })或Swoole\Coroutine::create(...)显式启动新协程。
哪些地方能直接写协程代码?
不是所有回调都能天然用协程客户端——Swoole 底层只在特定事件中自动创建协程环境:
-
HTTP Server:
onRequest回调内可直接使用Swoole\Coroutine\Http\Client、Redis、MySQL等协程客户端; -
WebSocket Server:
onMessage、onOpen中同样支持; -
TCP/UDP Server:
onReceive、onPacket也具备协程上下文; -
定时器:
Swoole\Timer::tick()和after()的回调函数也自动运行在协程中。
这些位置无需 go 包裹,写同步风格代码即可获得异步性能。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
协程客户端怎么用?以 Redis 为例
别再用 phpredis 扩展——它会阻塞整个协程。必须改用 Swoole 原生协程驱动:
- 实例化:
$redis = new Swoole\Coroutine\Redis(); - 连接:
$redis->connect('127.0.0.1', 6379);(注意:这是协程版 connect,非阻塞) - 执行命令:
$value = $redis->get('key');—— 这行看似同步,实则遇到网络等待时自动挂起,让出 CPU 给其他协程; - 错误处理:
if ($redis->errCode !== 0) { ... },协程 Redis 不抛异常,靠errCode判断。
同理,Swoole\Coroutine\MySQL、Swoole\Coroutine\Http\Client 使用方式高度一致:connect → query / get / post → 拿结果。
容易踩坑的几个点
协程强大,但违背规则就会失效或出错:
-
禁止混用同步扩展:在协程中调用
PDO::query()或file_get_contents()(未开启 Hook 时)会阻塞当前协程,拖垮并发能力; -
协程变量隔离:每个协程有独立栈,函数内定义的局部变量互不影响,但全局变量、静态变量仍共享,需加锁或改用协程本地存储(
Co::getuid()+ 数组缓存); -
超时控制必设:协程客户端默认无超时,
$redis->connect()或$client->get()可能无限等待,务必设置:$redis->setOption(Swoole\Coroutine\Redis::OPTION_CONNECT_TIMEOUT, 1);; -
连接不要复用跨协程:一个
Swoole\Coroutine\Redis实例只能被单个协程安全使用,多协程并发访问同一实例会导致数据错乱。

















