协程仅对Swoole Hook的IO操作生效;sleep()等未Hook函数会阻塞整个Worker;static变量跨请求持久化需改用Table/Redis或协程上下文;全局PDO等资源须用连接池隔离;reload不重载类定义,需在onWorkerStart动态加载。

协程不是“自动异步”,它只对 Swoole Hook 过的 IO 操作生效;没被 Hook 的函数(比如 sleep()、file_get_contents()、原生 PDO)在协程里照样阻塞整个 Worker。
为什么 sleep() 在协程里会卡死整个进程
因为 PHP 原生 sleep() 是系统调用,Swoole 默认不接管;它会让当前协程和所在 Worker 进程一起挂起 1 秒,期间无法响应任何新请求。
- 必须改用
Swoole\Coroutine::sleep()或Co::sleep() - 所有同步阻塞函数都要查文档确认是否被 Hook:比如
curl_exec()不行,但Swoole\Coroutine\Http\Client可以 - 用
strace跟踪进程系统调用,看到nanosleep就说明没走协程调度
static $counter 在 onRequest 里越加越大,怎么破
PHP-FPM 每次请求都重建脚本上下文,而 Swoole Worker 进程常驻内存,static 变量生命周期跨请求延续——这不是 bug,是设计使然。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 别在回调里用
static存状态,尤其不能用于计数、缓存或连接句柄 - 需要跨请求共享数据时,用
Swoole\Table(进程内共享)或Redis(多 Worker 共享) - 临时状态建议用协程上下文:
Co::getContext()+Co::setContext(),每个协程隔离
协程里用了 global $pdo,结果并发一高就报错
全局变量在 Worker 内所有协程间共享,多个协程同时读写同一个 PDO 实例会触发状态冲突,轻则返回错误结果,重则 core dump。
- 禁止在协程中复用非线程安全/非协程安全的资源句柄(PDO、mysqli、cURL handle)
- 必须用连接池:自己封装或用
hyperf/pool等组件,确保每次get()拿到的是独立实例 - 连接池
release()后要显式$conn->close()或重置状态,否则下次get()可能拿到脏连接
热更新后代码没生效,reload 像没按一样
Worker 进程只在启动时加载一次代码,reload 只是拉新进程、杀旧进程,并不会重新 include 或 require 文件。
- 类定义、函数声明等必须放在
onWorkerStart回调里动态载入,否则 reload 后仍是旧字节码 - Composer autoloader 若在
require vendor/autoload.php阶段完成,reload 后不会刷新映射表 - 验证是否生效:在
onWorkerStart里var_dump(new \ReflectionClass('YourClass')->getFileName())
最易被忽略的是协程上下文与资源生命周期的耦合关系——比如一个协程里 go() 启动子协程去查 Redis,父协程却提前退出,子协程可能还在跑,但它的 Co::getContext() 已不可靠。这种隐式依赖很难调试,得靠日志 + Co::stats() 定期采样才容易暴露。

















