reactor_num不能超过worker_num,否则会被自动截断为worker_num;其合理值应取min(CPU核数×2, worker_num),高配机器需显式设置以防默认仅启8个Reactor线程。

reactor_num不能超过worker_num
这是硬性限制。Swoole启动时会检查,如果reactor_num配置值大于worker_num,框架会自动把reactor_num设为等于worker_num,不会报错也不会警告——你可能根本意识不到配置被悄悄改了。
原因在于:Reactor线程只负责网络事件分发(accept、read、write),最终要把连接或数据投递给Worker进程处理;如果Reactor线程数多于Worker数,就可能出现多个Reactor争抢投递到少数Worker的情况,造成负载不均甚至队列积压。所以Swoole强制约束了这个上限。
- 例如配置
'reactor_num' => 16, 'worker_num' => 4→ 实际生效的reactor_num是 4 - 配置
'reactor_num' => 4, 'worker_num' => 16→ 实际生效的reactor_num是 4(合法) - 未显式设置
reactor_num时,Swoole默认用swoole_cpu_num(),但若该值 >worker_num,仍会被截断
worker_num决定实际并发处理能力的上限
worker_num 是真正跑业务逻辑的进程数,它直接影响QPS承载能力。而reactor_num只是“搬运工”数量,再高也救不了Worker不够导致的瓶颈。
常见误判是:看到CPU利用率不高,就盲目调高reactor_num,结果毫无提升——因为Worker早就在排队等CPU,不是Reactor没吃饱。
- 同步阻塞型业务(比如用PDO直连MySQL):每个Worker一次只能处理一个请求,
worker_num需按QPS × 平均响应时间(秒)估算,例如 1000 QPS × 0.1s = 至少100个Worker - 全异步IO业务(协程+async-redis/mysql):单个Worker可并发处理成百上千请求,
worker_num设为CPU核数的1–4倍更合理 -
reactor_num建议值 = min(CPU核数 × 2,worker_num),超过worker_num的部分纯属冗余
128核机器上reactor_num默认不是128
从Swoole 1.7.14起,超过8核的机器,reactor_num默认固定为8——不是CPU核数,也不是worker_num,就是8。这个行为容易被忽略,尤其在高配物理机或云主机上部署时。
这意味着:即使你有128核、配了128个Worker,不显式设置reactor_num,Reactor线程也只启8个,其余120核的网络事件处理能力基本闲置。
- 正确做法:显式写
'reactor_num' => 128或'reactor_num' => swoole_cpu_num() - 但注意:最大不能超
swoole_cpu_num() * 4,且必须 ≤worker_num - 验证方式:启动后用
ps -T -p $MASTER_PID查看线程数,Reactor线程名含reactor字样
task_worker_num和reactor_num/worker_num都无关
task_worker_num 是独立参数,只影响Task进程数量,和Reactor线程、Worker进程没有数值约束关系。但它依赖worker_num存在——因为只有Worker能调用$server->task()投递任务。
一个典型陷阱是:开了Task但忘了注册onTask和onFinish回调,Swoole直接拒绝启动,报错信息是 FATAL error: onTask callback is not set,而不是参数冲突类错误。
-
task_worker_num可以为0(禁用Task功能),也可以远大于worker_num(比如Worker=4,Task=32),只要内存够 - Task进程是同步阻塞的,不能用异步IO函数,所以它的数量应按「异步任务平均耗时 × 任务QPS」来算,而非CPU核数
- 它不参与网络事件循环,也不受
reactor_num调度影响
实际调参时最常被绕开的点是:先定worker_num,再根据它反推reactor_num上限,而不是反过来。很多线上问题根源不在Reactor不够快,而在Worker太饿。


















