swoole多进程间无法直接共享global或static变量,因各worker进程内存隔离;必须用swoole\table(推荐)、swoole\atomic(计数场景)或redis等外部存储实现共享。

Swoole 多进程间无法直接共享变量,global、static、超全局变量都只在当前 Worker 进程内有效;必须用共享内存或外部存储替代。
为什么不能直接用 global 或 static 变量
每个 Worker 进程是独立 fork 出来的,拥有完全隔离的内存空间。即使你在 onConnect 回调里往 $fds 数组 push 一个 fd,这个改动也只存在于当前进程的副本中,其他 Worker 完全感知不到。
- 常见错误现象:
var_dump($fds)在不同 Worker 中输出内容不一致,甚至为空 - 看似“写进去了”,实则是写进了各自进程的私有内存,不是同一块地址
- 强行用
pcntl_fork+shmop手动管理共享内存?可行但极易出错:字段对齐、序列化、锁同步全得自己兜底
Swoole\Table 是最稳妥的跨进程共享方案
它在主进程创建一块系统共享内存区域,所有 Worker 进程通过指针映射访问同一物理内存,底层自带行级自旋锁,PHP 层 API 干净简洁。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 必须在
onWorkerStart或 Server 启动前创建,不能在回调里 new —— 否则每个 Worker 都建一份独立 Table -
column()必须指定字符串字段长度,如TYPE_STRING, 64;超长会被静默截断,不会报错 -
set()返回false通常只有两个原因:Swoole\Table::ERR_TABLE_FULL(行数超限)或 key 冲突(重复 set 同一 key 且未开启覆盖) - 不支持嵌套数组或对象,存复杂结构得先
json_encode()成字符串,读取时再json_decode()
简单计数场景优先用 Swoole\Atomic
如果只是做请求计数、在线人数累加这类单一整型值同步,Swoole\Atomic 比 Table 更轻、更快、更安全——它基于 CPU 原子指令,无锁、无上下文切换开销。
- 只能存
int64,不能存字符串或浮点数;incr()返回的是操作后的新值,不是旧值 - 初始化值必须是整数,
new Swoole\Atomic(0)是标准写法;set(-1)合法,但set(9223372036854775808)会溢出变负 - 多个 Atomic 实例之间互不影响,但一个实例的所有 Worker 进程看到的是同一个值
- 注意:它不提供
getAndSet或 CAS 类接口,需要复合逻辑(如“读-改-写”)时仍得切回Table + Lock
别把 Redis 当 Table 用,也别把 Table 当 Redis 用
Redis 和 Swoole\Table 解决的是不同维度的问题:前者是跨机、持久、带协议的网络服务;后者是单机、瞬时、零拷贝的内存结构。混用会导致性能断层。
- 高频写场景(如每秒 3k+ 请求计数),走 Redis 的
INCR会因 TCP 往返、连接池争抢、序列化反序列化成为瓶颈 - 需要事务、模糊查询、TTL、发布订阅等能力?Table 不支持,必须上 Redis 或 MySQL
- Table 创建后容量不可扩容,预估不足会触发
ERR_TABLE_FULL;而 Redis 内存可动态伸缩(受限于物理内存) - Table 重启即丢数据,若需持久化,得配合 Redis/MySQL 做双写或定期 dump
真正难的不是选哪个组件,而是判断哪部分状态该放 Table、哪部分该交 Redis、哪部分根本不需要跨进程共享——比如 session 数据如果只被当前请求生命周期使用,压根不该进共享内存。










