Atomics.pause()
Atomics.pause() 静态方法提供了一种微等待原语,它提示 CPU 调用者正在忙等待(spinning)以访问共享资源。这允许系统减少分配给核心(如功耗)或线程的资源,而无需让出当前线程。
除了计时外,pause() 没有其他可观察的行为。具体行为取决于 CPU 架构和操作系统。例如,在 Intel x86 上,它可能是一个 pause 指令,根据 Intel 的优化手册。在某些平台上,它可能是一个空操作(no-op)。
语法
Atomics.pause()
Atomics.pause(durationHint)
参数
durationHint可选-
一个实现可以用来确定等待时间的整数。对于值
n + 1,实现等待的时间至少与给定值n的时间一样长。具体数字没有实际意义。在纳秒到几十纳秒的量级上,可能存在内部最大暂停时间的上限。这可以用来通过增加传递的durationHint来实现 退避策略。不能保证实现一定会利用此提示。
返回值
无(undefined)。
异常
TypeError-
如果
durationHint不是整数或undefined,则抛出错误。
示例
使用 Atomics.pause()
调用 Atomics.wait() 或 Atomics.waitAsync() 来等待访问共享内存会导致线程被调度出核心,并在等待结束后重新调度回核心。在高争用时期,这非常高效,因为访问共享内存可能需要一些时间。当争用较低时,通常更有效的方法是在不让出线程的情况下轮询锁:这种方法称为 忙等待 或 自旋锁。pause() 方法通过向 CPU 提供线程正在做什么的提示,从而降低其对资源的需求,使您能够更有效地自旋锁等待。
为了兼顾这两种情况,一种常见的方法是首先尝试自旋锁,希望能快速获取锁(争用低),然后在一段时间后如果仍未获得锁,则进行等待。如果我们已经通过自旋锁获取了锁,那么 wait() 调用将是一个空操作。
下面的示例显示了如何将这种方法与 Atomics.pause() 和 Atomics.wait() 结合使用。
警告:不建议在主线程上使用自旋锁,因为它会冻结整个页面。总的来说,除非经过非常仔细的设计,否则自旋锁的性能可能并不比常规等待更好。
// Imagine another thread also has access to this shared memory
const sab = new SharedArrayBuffer(1024);
const i32 = new Int32Array(sab);
// Fast path: spin the CPU for a short while
let spin = 0;
do {
if (Atomics.compareExchange(i32, 0, 0, 1) === 0) {
break;
}
Atomics.pause();
spin++;
} while (spin < 10);
// Slow path: wait for the lock
// This can only be called in a worker thread,
// because the main thread cannot be blocked
Atomics.wait(i32, 0, 1);
退避策略
durationHint 参数可用于实现退避策略。例如,线程可以从一个小的提示开始,并在每次迭代中指数级增加提示。这比多次调用 pause() 要好,因为在未 JIT 编译的代码中,函数调用本身就有很高的开销。
注意:实现可能根本不使用 durationHint,而是始终等待一个固定的时间。
// Exponential backoff
for (let hint = 1; hint < 1000; hint *= 2) {
Atomics.pause(hint);
}
// Linear backoff
for (let hint = 1; hint < 100; hint++) {
Atomics.pause(hint);
}
规范
| 规范 |
|---|
| Atomics.pause # Atomics.pause |
浏览器兼容性
加载中…