4. Atomics 原子化工具
约 1001 字大约 3 分钟
2025-04-30
以下是 JavaScript 中使用 Atomics
的完整指南,包含 基础用法、原子操作类型、同步机制 和 实际应用示例:
一、Atomics 基础使用流程
步骤 1:创建共享内存(SharedArrayBuffer)
// 主线程中创建 1KB 共享内存
const sharedBuffer = new SharedArrayBuffer(1024);
// 转换为可操作的定型数组(如 Int32Array)
const intArray = new Int32Array(sharedBuffer);
步骤 2:传递共享内存到 Web Worker
// 主线程
const worker = new Worker("worker.js");
worker.postMessage(sharedBuffer);
// Worker 线程(worker.js)
self.onmessage = (e) => {
const buffer = e.data;
const workerArray = new Int32Array(buffer);
};
步骤 3:使用 Atomics 操作共享内存
// 原子递增(线程安全)
Atomics.add(intArray, 0, 1);
// 原子读取(确保获取最新值)
const value = Atomics.load(intArray, 0);
二、Atomics 核心方法详解
1. 原子读写操作
方法 | 作用 | 示例 |
---|---|---|
Atomics.load(typedArray, index) | 原子读取值 | Atomics.load(intArray, 0) |
Atomics.store(typedArray, index, value) | 原子写入值 | Atomics.store(intArray, 0, 100) |
2. 原子数学运算
方法 | 操作 | 示例 |
---|---|---|
Atomics.add() | 加法 | Atomics.add(intArray, 0, 5) |
Atomics.sub() | 减法 | Atomics.sub(intArray, 0, 3) |
Atomics.and() | 按位与 | Atomics.and(intArray, 0, 0xFF) |
Atomics.or() | 按位或 | Atomics.or(intArray, 0, 0x01) |
Atomics.xor() | 按位异或 | Atomics.xor(intArray, 0, 0x0F) |
3. 同步控制方法
方法 | 用途 | 示例 |
---|---|---|
Atomics.compareExchange() | 比较并交换值(实现锁) | Atomics.compareExchange(intArray, 0, 0, 1) |
Atomics.wait() | 阻塞线程直到值变化 | Atomics.wait(intArray, 0, 0, 1000) |
Atomics.notify() | 唤醒等待的线程 | Atomics.notify(intArray, 0, 1) |
三、关键应用场景代码示例
场景 1:多线程计数器(无锁实现)
// 主线程初始化
const counterBuffer = new SharedArrayBuffer(4);
const counter = new Int32Array(counterBuffer);
// 启动 4 个 Worker 线程
for (let i = 0; i < 4; i++) {
new Worker("counter-worker.js").postMessage(counterBuffer);
}
// Worker 线程(counter-worker.js)
self.onmessage = (e) => {
const counter = new Int32Array(e.data);
for (let i = 0; i < 1000; i++) {
Atomics.add(counter, 0, 1); // 线程安全的原子递增
}
};
场景 2:生产者-消费者模型
// 共享内存结构
const buffer = new SharedArrayBuffer(1024);
const queue = {
data: new Int32Array(buffer),
index: 0,
size: 0,
maxSize: 256,
};
// 生产者线程
function produce(value) {
while (Atomics.load(queue.size) >= queue.maxSize) {
Atomics.wait(queue.size, 0, queue.maxSize); // 等待队列有空位
}
queue.data[queue.index] = value;
queue.index = (queue.index + 1) % queue.maxSize;
Atomics.add(queue.size, 0, 1);
Atomics.notify(queue.size, 0); // 通知消费者
}
// 消费者线程
function consume() {
while (Atomics.load(queue.size) <= 0) {
Atomics.wait(queue.size, 0, 0); // 等待数据
}
const value = queue.data[queue.index];
queue.index = (queue.index - 1 + queue.maxSize) % queue.maxSize;
Atomics.sub(queue.size, 0, 1);
Atomics.notify(queue.size, 0); // 通知生产者
return value;
}
场景 3:互斥锁(Mutex)实现
class Mutex {
constructor(sharedBuffer, index = 0) {
this.lock = new Int32Array(sharedBuffer, index, 1);
}
acquire() {
while (true) {
if (Atomics.compareExchange(this.lock, 0, 0, 1) === 0) {
return; // 成功获取锁
}
Atomics.wait(this.lock, 0, 1); // 等待锁释放
}
}
release() {
Atomics.store(this.lock, 0, 0);
Atomics.notify(this.lock, 0, 1); // 唤醒一个等待线程
}
}
// 使用示例
const mutexBuffer = new SharedArrayBuffer(4);
const mutex = new Mutex(mutexBuffer);
// 线程中安全操作
mutex.acquire();
try {
// 临界区代码
} finally {
mutex.release();
}
四、关键注意事项
1. 跨域隔离配置
使用 SharedArrayBuffer
需在服务器设置以下 HTTP 头:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
2. 线程安全原则
- 禁止直接读写共享内存:必须通过
Atomics
方法操作 - 避免忙等待:用
Atomics.wait()
替代循环检查 - 超时机制:为
wait()
设置合理超时防止死锁
3. 性能优化技巧
- 批量操作:减少原子操作次数(如累计多次加法后单次写入)
- 内存对齐:确保共享内存按数据类型对齐(如 Int32Array 起始位置为 4 字节倍数)
- 避免伪共享:不同线程操作的内存地址间隔至少 64 字节
五、浏览器兼容性方案
1. 检测支持性
if (!SharedArrayBuffer || !Atomics) {
throw new Error("Browser does not support SharedArrayBuffer");
}
2. 旧版浏览器降级
// 使用传统 postMessage 替代(牺牲性能)
if (typeof SharedArrayBuffer === "undefined") {
class FakeAtomics {
static add(buffer, index, value) {
const view = new Int32Array(buffer);
const old = view[index];
view[index] += value;
return old;
}
}
window.Atomics = FakeAtomics;
}
通过合理使用 Atomics
,您可以在 Web Workers 中实现高效且线程安全的并行计算。建议结合具体场景选择原子操作类型,并严格遵循同步规范以避免竞态条件。
更新日志
2025/8/24 08:17
查看所有更新日志
e7112
-1于