sharedarraybuffer + atomics 是 node.js 多 worker 下高效共享内存的原生方案,主进程创建并传递 sharedarraybuffer,worker 需重建 typedarray 视图,所有读写必须用 atomics 原子操作,配合 wait/notify 实现低开销同步。

SharedArrayBuffer + Atomics 是 Node.js 多 Worker 场景下实现高效、无锁、低延迟共享数据的原生方案,它绕过了序列化与消息拷贝开销,直接在多个独立 V8 实例间映射同一块内存。关键不在于“能不能传”,而在于“怎么安全地读写”——所有并发访问必须通过 Atomics 原子操作完成,否则必然出现竞态或数据损坏。
主进程统一创建并分发 SharedArrayBuffer
每个 Worker 的内存空间完全隔离,无法自动共享变量。必须由主进程(Master)一次性创建 SharedArrayBuffer,并通过 worker.postMessage() 将其引用传递给各 Worker。注意:只能传 buffer 对象本身,不能传 TypedArray 视图(如 Int32Array),否则 Worker 收到的是副本而非共享引用。
- 主进程中创建:
const sab = new SharedArrayBuffer(1024); const view = new Int32Array(sab); - 用
worker.postMessage({ type: 'INIT', buffer: sab })发送 - Worker 中接收后,必须用相同构造方式重建视图:
const view = new Int32Array(e.data.buffer);
所有读写必须经由 Atomics 方法
TypedArray 的普通赋值(view[0] = 1)或读取(view[0])不是原子操作,在多 Worker 并发下不可靠。必须使用 Atomics 提供的原子函数,它们能确保操作不可中断、线性一致。
- 计数器自增:
Atomics.add(view, 0, 1) - 条件更新(先比较再写):
Atomics.compareExchange(view, 0, expected, newValue),避免“读-判-写”三步拆分导致的中间态污染 - 标志位设置:
Atomics.or(view, 0, 1 (置第3位),比 store + load 更安全 - 读取务必用
Atomics.load(view, index),不要用view[index]
配合 wait/notify 实现轻量级同步等待
当某个 Worker 需要等待共享状态变化(例如等待令牌生成、任务就绪),可结合 Atomics.wait() 和 Atomics.notify() 实现无轮询阻塞等待,大幅降低 CPU 占用。
- Worker A 执行
Atomics.wait(view, 0, 0, 5000):若 view[0] 当前为 0,则挂起最多 5 秒 - Worker B 执行
Atomics.store(view, 0, 1)后调用Atomics.notify(view, 0, 1),唤醒至多 1 个等待者 - 注意:
wait()只接受 Int32Array,且需确保 COOP/COEP 策略已启用(Node.js 中无需 HTTP 头,但需启动时加--experimental-shared-array-buffer)
规避常见陷阱
很多看似合理的写法实际会破坏原子性或引发未定义行为:
- 禁止将
Atomics.load()结果直接用于 if 判断布尔逻辑,因为返回的是数字(如 0 或 1),不是 true/false;应显式比较:if (Atomics.load(view, 0) === 1) - 禁止用
++view[0]或view[0] += 1替代Atomics.add()—— 这是读+写两步,中间可能被其他 Worker 插入 - TypedArray 视图一旦绑定 SharedArrayBuffer,其长度和字节偏移不可变;需提前规划好内存布局(如前 4 字节存计数器、后 4 字节存状态码)
- Node.js 12+ 默认禁用 SharedArrayBuffer,启动时须加命令行参数:
node --experimental-shared-array-buffer server.js











