EventLoop 是 Swoole 异步行为的执行基座,绑定于 Worker 进程,驱动协程、定时器与 IO;信号仅 Master 可捕获;阻塞 Loop 会导致 Worker 假死。

EventLoop 不是“可选模块”,而是 Swoole 所有异步行为的执行基座;信号处理若未在 Master 进程中正确注册,Worker 会直接忽略 SIGTERM 等关键信号,导致进程无法优雅退出。
EventLoop 的生命周期绑定在 Worker 进程内
Swoole 启动后,每个 Worker 进程都会初始化一个独立的 EventLoop 实例,它从 $server->start() 调用起持续运行,直到进程退出。协程调度、定时器触发、Socket 读写回调,全部依赖该 Loop 实例驱动——不是全局共享,也不是按需创建。
常见错误现象:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 在
onRequest回调里手动调用swoole_event_add()注册文件描述符,但未确认当前是否处于协程环境(协程内默认禁用原生 event API) - 误以为
Co\run()启动的是新 Loop,实际它只是协程调度入口,底层仍复用 Worker 当前 Loop - 在 TaskWorker 中尝试使用
Co\Timer::after(),失败——TaskWorker 默认不启用协程 Hook,且无独立 Loop
实操建议:
- 所有协程化 IO 操作(如
Co\MySQL::query()、Co\Http\Client::get())必须确保已调用Swoole\Runtime::enableCoroutine() - 避免在协程中混用
swoole_event_*()系列函数,它们面向传统回调式编程,与协程调度器冲突 - 若需在非 Worker 进程(如 TaskWorker)中使用定时器,改用
Server::tick()或Server::after()(由 Master/Manager 进程统一管理)
信号只能由 Master 进程捕获和分发
Swoole 的信号处理模型严格遵循 POSIX 多进程规范:只有 Master 进程能接收并响应 SIGTERM、SIGHUP、SIGUSR1 等信号;Worker 和 TaskWorker 进程被设置为忽略这些信号,防止业务逻辑意外中断。
常见错误现象:
- 在
onWorkerStart中调用pcntl_signal(SIGTERM, $callback),发现完全不触发 - 向 Worker 进程 PID 发送
kill -15,进程无响应,只能kill -9强杀 - 误用
$server->addProcess()创建的自定义子进程未显式设置信号掩码,被 Master 的信号广播干扰
实操建议:
- 自定义信号处理逻辑(如热重启、配置重载)必须注册在
onManagerStart或通过$server->addSignal()(Swoole 4.5+)在 Master 进程中完成 - Worker 进程如需感知信号状态,应通过
Server::stats()或共享内存(Swoole\Table)轮询 Master 设置的标志位 - 若需向特定 Worker 发送指令,使用
$server->sendMessage()配合onPipeMessage,而非信号
EventLoop 阻塞会导致整个 Worker 卡死
EventLoop 是单线程事件驱动模型,一旦某个回调或协程执行耗时过长(如未加超时的 sleep(5)、同步 Redis get()、密集计算),就会阻塞 Loop,使该 Worker 无法处理任何新事件(包括心跳、定时器、新连接)。
常见错误现象:
- WebSocket 连接突然断连无心跳响应,查日志发现某次
onMessage处理耗时 8 秒 - 定时器延迟严重,
Server::tick(1000, ...)实际间隔变成 3~5 秒 - 并发压测时 QPS 突然归零,
strace -p $worker_pid显示进程卡在epoll_wait
实操建议:
- 所有可能阻塞的操作必须协程化或加超时:用
Co\Redis::get()替代Redis::get(),用Co\Http\Client::get(['timeout' => 3]) - CPU 密集型任务必须投递到 TaskWorker:
$server->task($data),禁止在 Worker 中做 base64_decode、json_encode 大数组等操作 - 启用
heartbeat_idle_time和heartbeat_check_interval配合onClose清理异常连接,避免坏连接长期占用 Loop
真正难处理的不是 Loop 怎么启动,而是它一旦开始运行,就再没有“暂停键”——所有代码都成了它的上下文,任何一次未设防的阻塞,都会让整个 Worker 进入假死状态,而这个状态不会报错,只会静默拖垮服务。

















