javascript基础从小白到高手系列一千九百八十三:原子读和写

浏览器的JavaScript 编译器和CPU 架构本身都有权限重排指令以提升程序执行效率。正常情况下,
JavaScript 的单线程环境是可以随时进行这种优化的。但多线程下的指令重排可能导致资源争用,而且
极难排错。
Atomics API 通过两种主要方式解决了这个问题。
 所有原子指令相互之间的顺序永远不会重排。
 使用原子读或原子写保证所有指令(包括原子和非原子指令)都不会相对原子读/写重新排序。
这意味着位于原子读/写之前的所有指令会在原子读/写发生前完成,而位于原子读/写之后的所有
指令会在原子读/写完成后才会开始。
除了读写缓冲区的值,Atomics.load()和Atomics.store()还可以构建“代码围栏”。JavaScript
引擎保证非原子指令可以相对于load()或store()本地重排,但这个重排不会侵犯原子读/写的边界。
以下代码演示了这种行为:
const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 执行非原子写
view[0] = 1;
// 非原子写可以保证在这个读操作之前完成,因此这里一定会读到1
console.log(Atomics.load(view, 0)); // 1
// 执行原子写
Atomics.store(view, 0, 2);
// 非原子读可以保证在原子写完成后发生,因此这里一定会读到2
console.log(view[0]); // 2
原子交换
为了保证连续、不间断的先读后写, Atomics API 提供了两种方法: exchange() 和
compareExchange()。Atomics.exchange()执行简单的交换,以保证其他线程不会中断值的交换:
const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引0 处写入3
Atomics.store(view, 0, 3);
// 从索引0 处读取值,然后在索引0 处写入4
console.log(Atomics.exchange(view, 0, 4)); // 3
// 从索引0 处读取值
console.log(Atomics.load(view, 0)); // 4
在多线程程序中,一个线程可能只希望在上次读取某个值之后没有其他线程修改该值的情况下才对
共享缓冲区执行写操作。如果这个值没有被修改,这个线程就可以安全地写入更新后的值;如果这个值被修改了,那么执行写操作将会破坏其他线程计算的值。对于这种任务,Atomics API 提供了compare-
Exchange()方法。这个方法只在目标索引处的值与预期值匹配时才会执行写操作。来看下面这个例子:
const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引0 处写入5
Atomics.store(view, 0, 5);
// 从缓冲区读取值
let initial = Atomics.load(view, 0);
// 对这个值执行非原子操作
let result = initial ** 2;
// 只在缓冲区未被修改的情况下才会向缓冲区写入新值
Atomics.compareExchange(view, 0, initial, result);
// 检查写入成功
console.log(Atomics.load(view, 0)); // 25
如果值不匹配,compareExchange()调用则什么也不做:
const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引0 处写入5
Atomics.store(view, 0, 5);
// 从缓冲区读取值
let initial = Atomics.load(view, 0);
// 对这个值执行非原子操作
let result = initial ** 2;
// 只在缓冲区未被修改的情况下才会向缓冲区写入新值
Atomics.compareExchange(view, 0, -1, result);
// 检查写入失败
console.log(Atomics.load(view, 0)); // 5

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值