SharedArrayBuffer + Atomics 是 Web 唯一支持多 Worker 无锁零拷贝通信的原生方案,但须同时满足跨域隔离、transfer list 正确传递、原子访问三条件;否则报错或静默失败。

SharedArrayBuffer + Atomics 是目前 Web 平台唯一能实现多 Worker 间真正无锁、零拷贝、低延迟通讯的原生方案,但必须满足跨域隔离、正确传递、原子访问三重条件,缺一不可。
SharedArrayBuffer 必须用 transfer list 传给 Worker,否则直接报错
主线程创建的 SharedArrayBuffer 对象不能像普通对象一样通过 postMessage() 直接发送——不加 transfer list 会触发 DATA_CLONE_ERR 或静默失败;加了但没写对,Worker 收到的是 null 或空视图。
- 正确写法:
worker.postMessage({ sab }, [sab])——sab必须同时出现在消息体和 transfer list 中 - 错误写法:
worker.postMessage({ sab })(只传引用,不转移所有权)或worker.postMessage(sab, [sab])(类型不匹配,Worker 接收后无法构造 TypedArray) - 多个 Worker 共享同一块内存时,每个都要单独调用
postMessage(..., [sab]),不能“广播”一次就完事 - Worker 内接收后必须立刻用
Int32Array或BigInt64Array包装,不能复用主线程的视图对象
Atomics.wait() 只能在 Worker 线程里调用,主线程调用直接 TypeError
Atomics.wait() 是阻塞式同步原语,浏览器明确禁止在主线程执行,否则抛出 TypeError: wait not allowed on main thread。这是硬性限制,不是兼容性问题。
- 只能在 Worker 脚本中使用:
Atomics.wait(sharedInts, 0, 0)是合法的;在主线程里写这行,代码立即中断 - 等待目标必须是
Int32Array(或BigInt64Array),传Float64Array会报RangeError: view is not an Int32Array - 第三个参数是“期望值”,不是“新值”——
Atomics.wait(arr, 0, 5)表示“等 arr[0] 变成非 5 的值”,如果当前就是 5,才会挂起;否则立刻返回"not-equal" - 超时单位是毫秒,但精度受限于浏览器调度,别指望精确到 1ms
共享内存布局要显式约定,否则各 Worker 读写位置互相覆盖
没有统一布局定义,多个 Worker 往同一块 SharedArrayBuffer 写数据,就像多人共用一张白纸却没划格子——谁写谁擦,结果不可控。
- 推荐前 4 字节做控制区:索引 0 存状态(0=空闲,1=就绪,2=写入中),索引 1 存数据长度,索引 2 存校验码
- 数据区从索引 4 开始,按固定结构排列(比如每 8 个
int32为一组,前 2 个存时间戳,后 6 个存向量值) - 避免用
view.length推算可用空间——不同 Worker 可能用不同视图切片,Int32Array(sab, 0, 100)和Int32Array(sab, 4, 96)会重叠 - 写入前务必用
Atomics.compareExchange()检查状态位,防止两个 Worker 同时进入“写入中”态
Atomics.notify() 唤醒数量要配平,漏 notify 或多 notify 都会导致死锁或忙等
Atomics.notify() 不是“发信号”,而是“叫醒指定数量的等待者”。少叫一个,那个 Worker 就永远卡在 wait();多叫一个,可能唤醒不该醒的 Worker,造成逻辑错乱。
- 典型模式:
Atomics.notify(sharedInts, 0, 1)—— 只唤醒 1 个在索引 0 等待的 Worker,适合生产者-消费者一对一 - 若多个 Worker 在同一位置等待(比如都
wait(sharedInts, 0, 0)),需根据业务决定唤醒全部:Atomics.notify(sharedInts, 0, Infinity) - notify 之前必须先
Atomics.store()改变被等待位置的值,否则wait()不会退出(它只响应“值变化”事件) - 没有“广播 notify”的快捷方式,每个等待位置都要单独 notify
最容易被忽略的是内存对齐与跨域头的耦合性:哪怕所有代码都写对了,只要服务器没返回 Cross-Origin-Embedder-Policy: require-corp,new SharedArrayBuffer(1024) 就会静默失败为 undefined,而 self.crossOriginIsolated 是唯一可靠的运行时判断依据。

















