Hyperf协程是基于Swoole/Swow在用户态实现的轻量级并发单元,以同步写法达成异步效果,需运行于Hyperf协程环境(如HttpServer、Command);co()、go()、Coroutine::create()均调用底层Swoole协程创建,但go()支持DI注入与AOP,Coroutine::create()不自动捕获异常;必须使用协程客户端(如Hyperf\Redis\Redis),禁用原生同步扩展;协程生命周期独立于请求,需用defer或WaitGroup显式清理资源。

Hyperf 协程不是 PHP 原生概念,而是基于 Swoole 或 Swow 扩展在用户态实现的轻量级并发执行单元,它让 PHP 代码能以同步写法达成异步效果,但必须运行在 Hyperf 启动的协程环境中(如 HttpServer、Command、Timer 等),否则 co() 或 go() 会静默失败或退化为同步执行。
协程不是线程,也不等于“多线程”
协程由用户代码调度,共享同一 OS 线程的内存空间,无上下文切换开销;而 PHP-FPM 每个请求独占一个进程,内存隔离但资源浪费严重。这意味着:
-
sleep(1)在传统 PHP 中阻塞整个进程,在协程中只挂起当前协程,其他协程继续运行 - 数据库查询、Redis 调用、HTTP 请求等 I/O 操作在协程中自动让出控制权,不阻塞事件循环
- 协程 ID(
Coroutine::id())是递增整数,每个协程有独立 ID,但生命周期由框架管理,不可手动销毁
co()、go() 和 Coroutine::create() 的实际差异
三者最终都调用 Swoole 底层 Swoole\Coroutine::create(),但行为边界不同:
-
co()是 Swoole 原生函数,Hyperf 兼容使用,但不触发 Hyperf 的协程生命周期钩子(如BeforeCoroutineHandle事件) -
go()是 Hyperf 封装的推荐方式,会自动注入依赖、绑定上下文,并支持 AOP 切面(如事务、日志) -
Coroutine::create()是 Hyperf 提供的静态方法,语义更明确,但需注意:它不自动捕获异常,未处理的异常会终止整个协程,且不走 DI 容器解析
协程内不能直接用 new Redis() 或 new PDO()
原生扩展(如 redis、mysqli)是同步阻塞的,放进协程里会拖垮整个事件循环。正确做法是:
- 必须使用 Hyperf 提供的协程客户端:
Hyperf\Redis\Redis、Hyperf\DbConnection\Db - 避免在协程中调用
exec()、shell_exec()、file_get_contents()等同步系统调用 - 第三方库若无协程适配,需用
Hyperf\Utils\Parallel包裹成子进程执行,或改用Swoole\Coroutine\Socket手动实现
真正容易被忽略的是协程生命周期与请求生命周期的错位:一个 HTTP 请求结束,其主协程退出,但你用 go() 启动的子协程可能还在跑——如果它持有 DB 连接、Redis 实例或未释放的 Channel,就会造成资源泄漏。务必用 WaitGroup 或 defer 显式管理清理逻辑。


















