协程是用户态轻量执行单元,运行于单线程内,仅在被 Hook 的 I/O 操作时挂起让出控制权;死循环无挂起点会导致 Worker 卡死;Co\Channel 是协程安全通信首选,Co\Stream 用于协程化文件/IPC,Co\WaitGroup 和 Co\Semaphore 实际使用较少且易误用。

协程不是线程,go() 启动的也不是新线程
协程是用户态调度的轻量执行单元,运行在单个 Worker 进程的单线程内。它不创建 OS 线程,也不抢占 CPU;只有遇到 co::sleep()、Co\MySQL->query()、Co\Http\Client->execute() 等被 Hook 的 I/O 操作时,才会挂起并让出控制权——此时事件循环继续处理其他就绪协程。
常见错误现象:go(function () { while (true) { echo "."; } }); 会彻底卡死整个 Worker,因为死循环中无任何挂起点,调度器无法介入。
- 必须确保每个协程内至少有一个可挂起操作(哪怕只是
co::sleep(0)) - 协程间不能靠
sleep()或usleep()让渡时间,它们会阻塞整个进程 -
Co\run()是协程容器入口,但仅需调用一次;重复嵌套会导致协程嵌套过深或调度异常
Co\Channel 是最常用且最可控的协程通信方式
Co\Channel 是 Swoole 提供的协程安全队列,底层基于共享内存 + 原子操作实现,无需加锁,支持跨协程 push()/pop(),是替代全局变量传递数据的首选。
使用场景:Worker 内多个协程协作完成一个请求(如并发查 DB + 调第三方 API + 合并结果),主协程等待子协程结果返回。
- 创建时建议指定容量:
new Co\Channel(1024),避免无限堆积导致内存暴涨 -
pop()默认阻塞,超时需显式传参:$channel->pop(3.0),否则可能永久挂起 - 不要在
onClose或onWorkerStop中尝试pop()未关闭的 Channel,会一直等待 - Channel 不跨 Worker 进程,也不能在 TaskWorker 中直接读写同一 Channel 实例
别把 Co\Socket 当管道用,Co\Stream 才是协程化文件流
很多同学误以为 Co\Socket 可用于协程间通信(比如父子协程传数据),但它本质是网络套接字封装,面向远程连接;本地通信应优先用 Co\Channel 或 Co\Stream。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
Co\Stream 是 Swoole 对 fopen() / fread() 等文件操作的协程化封装,支持非阻塞读写,可用于临时文件、日志缓冲、IPC 场景(配合 php://temp 或 php://memory)。
-
Co\Socket的connect()若目标不可达,会阻塞整个协程(除非已启用SWOOLE_HOOK_SOCKET) -
Co\Stream::open('php://temp', 'rw')创建内存流后,多个协程可安全读写同一资源句柄(因底层已协程化) - 用
Co\Stream替代file_get_contents()时,记得启用SWOOLE_HOOK_FILE,否则仍会同步阻塞
Co\WaitGroup 和 Co\Semaphore 容易被高估,实际用得少
这两个组件语义清晰,但真实业务中极少直接使用:Co\WaitGroup 适合等固定数量协程结束,但多数场景用 Channel + pop() 更自然;Co\Semaphore 类似信号量,常被误用于“限制并发数”,但更稳妥的做法是用连接池限流或 Co\Channel 控制生产者速率。
典型误用:$sem = new Co\Semaphore(5); $sem->wait(); /* do work */ $sem->signal(); ——若某协程抛异常未执行 signal(),信号量将永久卡死。
-
Co\WaitGroup的add()必须在go()外调用,否则计数不同步 -
Co\Semaphore无超时机制,wait()可能永远阻塞,生产环境慎用 - 真正需要限流时,优先考虑
Co\Channel(10)作令牌桶,或用 Redis + Lua 做分布式控制
协程通信的关键不在“能用什么”,而在“为什么不用别的”。Channel 的边界、Stream 的协议适配、Semaphore 的异常兜底——这些地方不写注释、不加监控,上线后就是静默雪崩点。

















