Hyperf协程中不可使用sleep(),因其会阻塞整个协程调度器;应改用Co::sleep()或Hyperf\Coroutine\Coroutine::sleep()实现异步等待。

Hyperf协程里不能用 sleep()
Hyperf 是基于 Swoole 协程的框架,主线程是协程调度器管理的,sleep() 是同步阻塞函数,会直接挂起整个协程调度器线程,导致其他协程无法运行 —— 这不是“协程 sleep”,而是“杀死协程并发能力”。你看到服务卡住、接口超时、CPU 低但 QPS 暴跌,大概率就是误用了 sleep()。
- 真实现象:
sleep(1)后整个 Worker 进程卡死 1 秒,所有正在运行的协程(包括数据库查询、HTTP 调用)全部暂停 - 正确替代:必须用协程友好的异步等待,即
Co::sleep() - 注意命名空间:
Co::sleep()是 Swoole 提供的协程版 sleep,不是 PHP 内置函数,也不在Hyperf\Coroutine下
Co::sleep() 的用法和参数细节
Co::sleep() 接收秒为单位的浮点数,支持毫秒级精度(比如 0.1 表示 100ms),底层调用的是 co::usleep() 封装,安全且可中断。
- 基本写法:
Co::sleep(2)—— 睡 2 秒;Co::sleep(0.05)—— 睡 50 毫秒 - 不支持负数或非数字,传错会抛出
Swoole\Exception - 在
go匿名函数、@Inject注入的服务方法、Command的handle()中均可直接调用 - 若在非协程环境(如
php bin/hyperf.php start之外的 CLI 脚本)中调用,会报错 “must be called in coroutines”
Hyperf 里更推荐用 Coroutine::sleep()?
Hyperf 自己封装了 Hyperf\Coroutine\Coroutine::sleep(),它只是对 Co::sleep() 的一层代理,行为完全一致。但要注意:
- 必须
use Hyperf\Coroutine\Coroutine;才能调用,否则会找不到类 - 部分旧版本(如 v2.2 之前)该类不存在,直接用
Co::sleep()更稳妥 - 没有额外功能增强,性能无差异,纯属风格选择 —— 官方文档和核心代码里也多用
Co::sleep() - 别混淆
Coroutine::create()和Coroutine::sleep(),后者不创建新协程,只挂起当前协程
实际场景中的典型错误和替代方案
常见于轮询、限流、重试逻辑。比如“每 3 秒查一次 Redis”,如果写成 while (true) { $this->check(); sleep(3); },整个协程就废了。
- ✅ 正确写法:
while (true) { $this->check(); Co::sleep(3); } - ⚠️ 注意信号中断:
Co::sleep()可被协程取消(如父协程 exit),但不会自动响应 Unix signal,需配合Co::wait()或事件循环做优雅退出 - ? 更健壮的重试建议:用
Hyperf\Retry\Retry组件 +Co::sleep(),避免手写死循环 - ? 切勿在
__destruct()或finally块里调用Co::sleep()—— 协程可能已关闭,行为未定义
Hyperf 协程里 sleep 的本质,是让当前协程让出 CPU 并注册一个定时唤醒事件,而不是“停掉线程”。这个边界一旦模糊,就容易写出伪协程代码。真正难的不是记住用哪个函数,而是在 every sleep、every file_get_contents、every curl_exec 出现的地方,都下意识问一句:它是否协程安全?











