Node.js中如何操作原子操作?

来源:建站作者:木下头衔:网络博主
导读:本期聚焦于小伙伴创作的《Node.js中如何操作原子操作?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Node.js中如何操作原子操作?》有用,将其分享出去将是对创作者最好的鼓励。

Node.js中操作原子操作主要依赖SharedArrayBuffer和Atomics对象实现,这两个特性从Node.js 10版本开始正式支持,能够在多线程共享内存的场景下保证操作的原子性,避免数据竞争问题。

Node.js中如何操作原子操作?

原子操作的基本概念

原子操作指的是不可被中断的一个或一组操作,在执行过程中不会被其他线程干扰,要么全部执行完成,要么完全不执行。在多线程场景下,多个线程同时修改同一块共享内存时,如果没有原子操作保证,很容易出现数据不一致的问题。比如两个线程同时对一个数值做加一操作,最终得到的结果可能不符合预期。

Node.js中原子操作的基础依赖

SharedArrayBuffer

SharedArrayBuffer是共享内存的缓冲区,多个Worker线程可以访问同一份SharedArrayBuffer实例,实现内存共享。普通的ArrayBuffer是每个线程独享的,无法实现共享内存场景下的数据交互。

Atomics对象

Atomics是一个内置对象,提供了一些静态方法,用来对SharedArrayBuffer进行原子级别的操作,所有方法都是原子性的,不会被其他线程打断。它支持的操作包括读写、加减、比较交换等。

Atomics常用方法说明

方法名作用说明
Atomics.load(typedArray, index)原子性地从typedArray的指定index位置读取数值
Atomics.store(typedArray, index, value)原子性地将value写入typedArray的指定index位置
Atomics.add(typedArray, index, value)原子性地将typedArray指定位置的数值加上value,返回加法前的值
Atomics.sub(typedArray, index, value)原子性地将typedArray指定位置的数值减去value,返回减法前的值
Atomics.compareExchange(typedArray, index, expectedValue, replacementValue)如果typedArray指定位置的当前值等于expectedValue,就原子性地替换为replacementValue,返回原来的值
Atomics.wait(typedArray, index, value, timeout)如果typedArray指定位置的当前值等于value,就阻塞当前线程直到被唤醒或者超时,返回字符串表示状态
Atomics.notify(typedArray, index, count)唤醒在typedArray指定位置等待的线程,最多唤醒count个,返回实际唤醒的数量

Node.js中原子操作示例

基础读写操作示例

下面的代码演示了如何使用Atomics进行原子性的读写操作:

// 创建长度为1的Int32Array,基于SharedArrayBuffer
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);

// 原子性写入数值10
Atomics.store(int32, 0, 10);
console.log('写入后的数值:', Atomics.load(int32, 0)); // 输出10

// 原子性加5
const oldValue = Atomics.add(int32, 0, 5);
console.log('加法前的值:', oldValue); // 输出10
console.log('加法后的数值:', Atomics.load(int32, 0)); // 输出15

// 原子性减3
Atomics.sub(int32, 0, 3);
console.log('减法后的数值:', Atomics.load(int32, 0)); // 输出12

多线程场景下的原子操作示例

下面的代码使用Worker线程模拟多线程场景,演示原子操作如何避免数据竞争:

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
    // 主线程创建共享内存
    const sab = new SharedArrayBuffer(4);
    const int32 = new Int32Array(sab);
    Atomics.store(int32, 0, 0);

    // 创建两个工作线程
    const worker1 = new Worker(__filename, { workerData: sab });
    const worker2 = new Worker(__filename, { workerData: sab });

    // 等待两个线程执行完成
    let finished = 0;
    const checkFinish = () => {
        finished++;
        if (finished === 2) {
            // 最终数值应该是200,因为每个线程加100次,每次加1
            console.log('最终共享内存的数值:', Atomics.load(int32, 0));
        }
    };
    worker1.on('exit', checkFinish);
    worker2.on('exit', checkFinish);
} else {
    // 工作线程逻辑
    const sab = workerData;
    const int32 = new Int32Array(sab);
    // 每个线程对共享数值加100次
    for (let i = 0; i < 100; i++) {
        // 原子性加1,避免数据竞争
        Atomics.add(int32, 0, 1);
    }
    parentPort.postMessage('done');
}

注意事项

  • Atomics的所有方法只能操作基于SharedArrayBuffer的TypedArray,比如Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array,不支持普通的数组或者Object。
  • 使用SharedArrayBuffer需要Node.js运行在合适的环境下,部分旧版本或者特殊配置的环境可能不支持。
  • Atomics.wait只能在主线程或者Worker线程中使用,不能在不可等待的上下文中调用,否则会报错。
  • 原子操作虽然能保证操作的原子性,但是过多使用可能会导致性能开销,需要根据实际场景合理选择。

Node.js原子操作AtomicsSharedArrayBuffer多线程修改时间:2026-06-26 19:42:19

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。