如何在不同Worker中的两个WebAssembly实例之间实现内存共享
跨Worker同模块WASM实例内存共享实现方案
前置环境检查
- 必须在站点服务端配置两个安全响应头,这是运行时启用
SharedArrayBuffer的强制要求,缺省情况下就算标记了共享属性也只会返回普通ArrayBuffer:Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
- 本地开发可通过给浏览器添加启动参数
--enable-features=SharedArrayBuffer临时绕过头校验,生产环境必须配置上述响应头。
WASM模块配置要求
- 模块的内存声明必须同时指定
shared属性和最大内存上限,缺少最大内存配置的共享声明不生效:- 手写WAT的声明示例:
(import "env" "memory" (memory $mem 1 10 shared))(初始1页=64KB,最大10页,开启共享) - Emscripten编译参数:
-s SHARED_MEMORY=1 -s MAXIMUM_MEMORY=10485760(最大内存设为10MB,可按需调整)
- 手写WAT的声明示例:
内存创建与实例化流程
- 主线程统一创建共享内存,不要在两个Worker内分别创建内存:
const sharedMemory = new WebAssembly.Memory({ initial: 1, // 初始页数,1页=64KB maximum: 10, // 最大页数,必须和WASM模块声明一致 shared: true });
- 用
postMessage将sharedMemory直接传递给派生Worker,WebAssembly.Memory属于可结构化克隆对象,传递后两个Worker拿到的是同一块内存的引用,不要只传递sharedMemory.buffer。 - 两个Worker实例化WASM模块时,统一传入外部的共享内存作为导入项,不要使用模块默认创建的内存:
// 主Worker和派生Worker的实例化逻辑一致,sharedMemory为传入的共享内存实例 const wasmInstance = await WebAssembly.instantiate(wasmModule, { env: { memory: sharedMemory } });
- 此时任意线程访问
wasmInstance.exports.memory.buffer都会得到SharedArrayBuffer类型,修改后的数据会自动在双线程同步。
注意事项
- 多线程读写共享内存时,WASM侧需使用原子操作指令(
atomic.load/atomic.store等),JS侧需使用Atomics对象读写,避免出现数据竞争和读写顺序异常。
内容的提问来源于stack exchange,提问作者Denis Belov
相关产品推荐
相关产品推荐

