JavaScript中的Atomics与SharedArrayBuffer
字数 669 2025-11-11 10:02:59

JavaScript中的Atomics与SharedArrayBuffer

描述
Atomics对象与SharedArrayBuffer是JavaScript中用于处理多线程并发操作的核心API。SharedArrayBuffer允许在多个Web Worker线程间共享内存,而Atomics提供了一套原子操作方法,确保在多线程环境下对共享内存的操作是线程安全的。

为什么需要共享内存

  1. 传统Web Worker通信使用postMessage需要数据序列化/反序列化,当数据量大时性能开销显著
  2. 共享内存允许多个线程直接读写同一块内存区域,避免数据拷贝
  3. 适用于高性能计算、实时数据处理等场景

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核心方法

  1. 原子读写操作:
// 原子存储(写)
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
  1. 原子交换操作:
// 原子交换
Atomics.exchange(intArray, index, value) // 设置新值,返回旧值

// 比较交换(CAS)
Atomics.compareExchange(intArray, index, expectedValue, replacementValue)
// 只有当当前值等于expectedValue时才替换为replacementValue
// 返回实际读取到的值
  1. 线程同步操作:
// 等待和通知(用于线程间协调)
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);
};

注意事项

  1. 同源策略:共享内存受浏览器同源策略限制
  2. 跨域隔离:需要设置Cross-Origin-Opener-Policy和Cross-Origin-Embedder-Policy头
  3. 性能考虑:原子操作比普通操作慢,仅在必要时使用
  4. 死锁风险:不当使用wait/notify可能导致死锁

适用场景

  • 高性能计算(如图像处理、物理模拟)
  • 实时数据流处理
  • 游戏开发中的状态同步
  • 科学计算和数据分析

通过合理使用SharedArrayBuffer和Atomics,可以在保持JavaScript单线程编程模型的同时,实现高效的多线程并发处理。

JavaScript中的Atomics与SharedArrayBuffer 描述 Atomics对象与SharedArrayBuffer是JavaScript中用于处理多线程并发操作的核心API。SharedArrayBuffer允许在多个Web Worker线程间共享内存,而Atomics提供了一套原子操作方法,确保在多线程环境下对共享内存的操作是线程安全的。 为什么需要共享内存 传统Web Worker通信使用postMessage需要数据序列化/反序列化,当数据量大时性能开销显著 共享内存允许多个线程直接读写同一块内存区域,避免数据拷贝 适用于高性能计算、实时数据处理等场景 SharedArrayBuffer基本使用 原子操作的必要性 当多个线程同时修改同一内存位置时会出现竞态条件: Atomics核心方法 原子读写操作: 原子交换操作: 线程同步操作: 完整示例:生产者-消费者模型 注意事项 同源策略:共享内存受浏览器同源策略限制 跨域隔离:需要设置Cross-Origin-Opener-Policy和Cross-Origin-Embedder-Policy头 性能考虑:原子操作比普通操作慢,仅在必要时使用 死锁风险:不当使用wait/notify可能导致死锁 适用场景 高性能计算(如图像处理、物理模拟) 实时数据流处理 游戏开发中的状态同步 科学计算和数据分析 通过合理使用SharedArrayBuffer和Atomics,可以在保持JavaScript单线程编程模型的同时,实现高效的多线程并发处理。