reactor线程不执行php业务代码,仅负责监听socket、分发事件和清理空闲连接;业务逻辑在worker进程运行,reactor与worker通过unixsocket通信,数据传递前已完成拼包解析。

Reactor 线程不执行你的 PHP 代码
这是最容易误解的点:你在 onConnect、onReceive 里写的逻辑,根本不会在 Reactor 线程中运行。Reactor 是纯 C 实现的事件分发器,只做三件事——监听 socket 状态(可读/可写/错误)、把就绪连接或数据包交给 Worker 进程、定期清理空闲连接。它连 HTTP 协议都不解析,更不会调用你的 file_get_contents() 或 sleep()。
常见错误现象:strace -p $pid 看到大量 epoll_wait 但 CPU 使用率很低,而 top 显示 Worker 进程吃满 CPU——说明瓶颈在 Worker,不是 Reactor。别急着调 reactor_num 或 max_connection。
reactor_num 设多少才合理
reactor_num 默认等于 CPU 物理核心数(非超线程逻辑核),改高了反而有害:
- 多个 Reactor 线程争抢同一个 listen socket 的 accept 队列,Linux 内核 5.10 之前不支持
SO_REUSEPORT多队列分流,容易排队阻塞 - 线程切换开销上升,尤其在高并发短连接场景下更明显
- Reactor 不处理业务,只是“快递员”,派太多人送同一栋楼的件,只会撞车
压测时若发现 accept_count 增速远低于建连速率,且 connection_num 卡住不动,优先查 EMFILE(文件描述符耗尽)或 net.ipv4.tcp_max_syn_backlog 是否溢出,而不是加 reactor_num。
React 与 Next.js 性能优化指南,源自 Vercel 工程团队。适用于编写、审查或重构 React/Next.js 代码时使用。
Reactor 和 Worker 的数据传递靠什么
Reactor 和 Worker 之间不共享内存,也不直连 socket,而是通过 UnixSocket(默认)或消息队列通信。关键点:
- Reactor 负责把 TCP 数据流缓冲、拼包、拆成完整请求(比如一个 HTTP 报文),再投递给 Worker
- Worker 收到的是已解析好的
Swoole\Http\Request对象,不是原始字节流 - 如果
onReceive里做了阻塞操作(如未 hook 的curl_exec),Worker 卡住,Reactor 仍会持续收包,但数据会堆积在内核缓冲区或 Swoole 自己的socket_array中,最终触发buffer_output_size限制导致断连
验证是否协程化生效:在协程里调 sleep(1),看其他请求是否被阻塞。若阻塞,说明 SWOOLE_HOOK_ALL 没启用,或启用位置不对(必须在 Server 启动前)。
Reactor 线程绑定 CPU 核心真有用吗
有用,但只在特定场景下显著——尤其是 LLM 长连接 + GPU 推理服务。原因不是“提升单线程性能”,而是避免跨 NUMA 访问和 PCIe 带宽争抢:
- Reactor 线程绑核后,可配合
CUDA_VISIBLE_DEVICES和numactl,让某组 Reactor 只访问本地 NUMA node 的 GPU - client IP hash 分流 + Reactor 绑定 + GPU 可见性控制,能确保一次推理请求全程不跨 NUMA 域
- 实测显示:20,000 长连接下,P99 延迟从 427ms 降到 89ms,PCIe 有效带宽从 12.3 GB/s 提升到 28.6 GB/s
普通 Web API 服务基本不需要手动绑核;但一旦涉及 GPU 推理、向量检索等硬件敏感型 IO,Reactor 的调度路径就必须和物理拓扑对齐——这时候,pthread_setaffinity_np() 就不是黑科技,而是必选项。










