barrier::wait() 不返回的最常见原因是子协程未正常退出或$barrier未通过use正确传递,导致引用计数无法减至0;此外重复调用wait()、混用不同扩展的barrier类、或http场景中未设超时也会引发永久挂起。

协程屏障(Barrier)不是 WaitGroup 的替代品,而是语义更严格的“一次性同步点”——它只等所有子协程退出,不关心返回值或执行状态;用错场景或漏传引用,会直接导致 Barrier::wait() 永久挂起。
为什么 Barrier::wait() 一直不返回?
最常见原因是子协程没真正“退出”,或者 $barrier 没被正确传递进子协程作用域。
- 子协程里没执行完就提前 return、抛异常未捕获、或调用了
exit(),会导致引用计数未减到 0 - 忘记在
use中传入$barrier,PHP 不会自动闭包捕获,子协程根本没持引用,Barrier析构时引用计数始终 ≥1 - 误把
Barrier::create()或Barrier::make()放在循环外但重复调用wait()——Barrier实例不可重用,第二次wait()会卡死
Barrier::create() 和 Barrier::make() 有什么区别?
本质相同,只是来源不同:前者来自 Workerman\Coroutine\Barrier,后者来自 Swoole\Coroutine\Barrier。二者 API 完全一致,但不能混用。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- Workerman 5.1+ 自带的
Barrier::create()仅在workerman>=5.1.0且使用Swoole/Swow/Fiber驱动时可用 - Swoole 扩展原生的
Barrier::make()要求 Swoole >= 4.8.0(实际推荐 5.0+),且必须已启用协程运行时:Swoole\Runtime::enableCoroutine() - 若项目同时引入 Workerman 和 Swoole 扩展,务必统一使用同一套 Barrier,否则
wait()可能因类型不匹配静默失败
在 HTTP 请求处理中怎么安全用 Barrier?
HTTP 场景下最易踩的坑是“协程生命周期短于 Barrier 等待时间”,尤其当子协程发起远程调用但超时未设或服务端响应慢时。
- 必须给
Barrier::wait()加$timeout参数,例如Barrier::wait($barrier, 3000)(单位毫秒),避免请求永远卡住 - 子协程内所有 IO 操作(如
Swoole\Coroutine\Http\Client)需确保已开启对应 Hook,否则阻塞整个 Worker 进程,Barrier 就失去了意义 - 不要在
onMessage或onRequest回调外创建 Barrier;它的生命周期应严格绑定单次请求上下文,否则可能跨请求残留引用
Barrier 的核心约束在于“一次性 + 引用计数驱动”,它不提供错误传播、不支持取消、也不记录子协程状态。如果你需要收集结果、重试或判断成功失败,该换 WaitGroup + Channel 组合,而不是硬套 Barrier。










