JavaScript中的Atomics与SharedArrayBuffer
字数 669 2025-11-11 10:02:59
JavaScript中的Atomics与SharedArrayBuffer
描述
Atomics对象与SharedArrayBuffer是JavaScript中用于处理多线程并发操作的核心API。SharedArrayBuffer允许在多个Web Worker线程间共享内存,而Atomics提供了一套原子操作方法,确保在多线程环境下对共享内存的操作是线程安全的。
为什么需要共享内存
- 传统Web Worker通信使用postMessage需要数据序列化/反序列化,当数据量大时性能开销显著
- 共享内存允许多个线程直接读写同一块内存区域,避免数据拷贝
- 适用于高性能计算、实时数据处理等场景
SharedArrayBuffer基本使用
// 主线程
const sharedBuffer = new SharedArrayBuffer(16); // 创建16字节共享内存
const intArray = new Int32Array(sharedBuffer); // 创建视图操作内存
// 创建工作线程并共享内存
const worker = new Worker('worker.js');
worker.postMessage({ buffer: sharedBuffer });
// 工作线程(worker.js)
self.onmessage = function(e) {
const sharedBuffer = e.data.buffer;
const intArray = new Int32Array(sharedBuffer);
// 现在主线程和工作线程可以操作同一块内存
};
原子操作的必要性
当多个线程同时修改同一内存位置时会出现竞态条件:
// 非原子操作的问题示例
// 线程1读取值为100,准备加1
// 线程2同时读取值100,也准备加1
// 两个线程都写入101,而不是预期的102
Atomics核心方法
- 原子读写操作:
// 原子存储(写)
Atomics.store(intArray, index, value) // 将value存入intArray[index]
// 原子加载(读)
Atomics.load(intArray, index) // 返回intArray[index]的值
// 原子加法
Atomics.add(intArray, index, value) // 原子执行intArray[index] += value
// 原子减法
Atomics.sub(intArray, index, value) // 原子执行intArray[index] -= value
- 原子交换操作:
// 原子交换
Atomics.exchange(intArray, index, value) // 设置新值,返回旧值
// 比较交换(CAS)
Atomics.compareExchange(intArray, index, expectedValue, replacementValue)
// 只有当当前值等于expectedValue时才替换为replacementValue
// 返回实际读取到的值
- 线程同步操作:
// 等待和通知(用于线程间协调)
Atomics.wait(intArray, index, expectedValue, timeout)
// 如果intArray[index]等于expectedValue,则线程进入等待状态
Atomics.notify(intArray, index, count)
// 唤醒在intArray[index]上等待的count个线程
完整示例:生产者-消费者模型
// 主线程(生产者)
const sharedBuffer = new SharedArrayBuffer(16);
const intArray = new Int32Array(sharedBuffer);
// 初始化:0=数据就绪标志,1=数据值
Atomics.store(intArray, 0, 0); // 数据未就绪
const worker = new Worker('consumer.js');
worker.postMessage({ buffer: sharedBuffer });
// 生产数据
setTimeout(() => {
Atomics.store(intArray, 1, 42); // 写入数据
Atomics.store(intArray, 0, 1); // 标记数据就绪
Atomics.notify(intArray, 0, 1); // 通知消费者
}, 1000);
// 消费者线程(consumer.js)
self.onmessage = function(e) {
const intArray = new Int32Array(e.data.buffer);
// 等待数据就绪
Atomics.wait(intArray, 0, 0); // 等待直到intArray[0]不为0
const data = Atomics.load(intArray, 1); // 读取数据
console.log('消费数据:', data);
};
注意事项
- 同源策略:共享内存受浏览器同源策略限制
- 跨域隔离:需要设置Cross-Origin-Opener-Policy和Cross-Origin-Embedder-Policy头
- 性能考虑:原子操作比普通操作慢,仅在必要时使用
- 死锁风险:不当使用wait/notify可能导致死锁
适用场景
- 高性能计算(如图像处理、物理模拟)
- 实时数据流处理
- 游戏开发中的状态同步
- 科学计算和数据分析
通过合理使用SharedArrayBuffer和Atomics,可以在保持JavaScript单线程编程模型的同时,实现高效的多线程并发处理。