sharedarraybuffer 必须启用跨域隔离(coop/coep 响应头),否则 new sharedarraybuffer() 抛 typeerror;atomics.compareexchange 是唯一安全的读-改-写原语;int32array 视图须基于同一 sharedbuffer 引用,传递时需 postmessage 的 transfer list;wasm 多线程比 js worker 更适合数值密集计算。

SharedArrayBuffer 必须启用跨域隔离才能用
不配 COOP/COEP 响应头,new SharedArrayBuffer() 会直接抛出 TypeError: SharedArrayBuffer is not supported in this context。这不是浏览器版本问题,而是硬性安全策略——2026 年所有主流浏览器(Chrome 124+、Firefox 125+、Safari 17.4+)都已强制执行。
服务端必须返回这两个响应头:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
开发时若用 Vite,可在 vite.config.js 的 server.headers 中加;用 Express,则用 res.set();本地测试也可临时用 npx http-server -p 8080 --cors --headers 配合自定义 header 文件。
Atomics.compareExchange 是唯一安全的“读-改-写”原语
想实现带条件的更新(比如“仅当当前值为 0 时才设为 1”),不能拆成 Atomics.load() + if + Atomics.store()。中间空隙会被其他线程插入,导致逻辑失效。
正确写法只有一种:
const ia = new Int32Array(sharedBuffer);
let expected = 0;
let desired = 1;
while (Atomics.compareExchange(ia, 0, expected, desired) !== expected) {
expected = Atomics.load(ia, 0);
}
这个循环不是性能缺陷,而是原子语义必需:它确保整个判断+赋值是不可分割的。常见误用包括用 Atomics.or() 模拟布尔标志位后直接 if (Atomics.load(ia, 0)) 判断——load 返回的是数字,不是布尔值,且无法保证读到的值未被覆盖。
Int32Array 视图必须与 SharedArrayBuffer 生命周期对齐
主线程创建 sharedBuffer 后,所有 Worker 接收并构造 Int32Array 视图时,必须用同一个 buffer 引用。如果在 Worker 内部重新 new SharedArrayBuffer(),哪怕大小相同,也是完全独立的内存块,无法共享数据。
传递方式只能是:
- 主线程
worker.postMessage(sharedBuffer, [sharedBuffer])(注意 transfer list) - Worker 内
self.onmessage = e => { const ia = new Int32Array(e.data); }
漏传 transfer list 会导致结构化克隆,实际上传的是副本,后续所有 Atomics 操作都无效。这是最隐蔽的调试陷阱之一——代码不报错,但数值就是不更新。
WASM 多线程算子比纯 JS Worker 更适合数值密集场景
如果你的算子本质是循环累加、矩阵乘、FFT 等固定模式计算,别硬写 JS Worker + Atomics。C/Rust 编译出的多线程 WASM 模块在 2026 年已稳定支持 pthread 和共享内存,实测吞吐量高 3–8 倍,且无 JS GC 干扰。
关键编译参数(Emscripten):
emcc -O3 compute.c \ -s WASM=1 \ -s USE_PTHREADS=1 \ -s PTHREAD_POOL_SIZE=4 \ -s SHARED_MEMORY=1 \ -s EXPORTED_FUNCTIONS='["_run_parallel_sum"]' \ -o compute.js
加载后,主线程只需调用 Module._run_parallel_sum(bufferPtr),bufferPtr 指向由 Module._malloc() 分配、且已用 Module.HEAP32.set() 填入数据的共享内存区域。WASM 线程池自动分片执行,无需手动管理 Worker 实例数或通信协议。
真正难的不是写算子,而是确认你的 WASM 模块是否真的启用了共享内存——检查生成的 .wasm 二进制中是否有 (memory (shared ...)) 声明,以及运行时 Module.wasmMemory?.shared 是否为 true。











