Javascript 简明教程
JavaScript - Atomics Objects
JavaScript 中的 Atomics 对象提供了一组用于对 SharedArrayBuffer 对象执行原子操作的静态方法。原子操作是保证在单一步骤中完成的操作,不会被其他线程中断。这使其对于实现并发数据结构和算法非常有用。
The Atomics object in JavaScript provides a set of static methods for performing atomic operations on SharedArrayBuffer objects. Atomic operations are operations that are guaranteed to be completed in a single step, without being interrupted by other threads. This makes them useful for implementing concurrent data structures and algorithms.
作为 ECMAScript 标准的一部分,JavaScript 中的 Atomics 对象作为在多线程环境中管理共享内存的关键工具。让我们更详细地了解原子操作的基本概念:
The Atomics object in JavaScript, as part of the ECMAScript standard, serves as a crucial tool for managing shared memory in a multi-threaded environment. Let’s understand the basic concept of atomic operations in more detail:
Atomics Object
Atomics 对象是内置的 JavaScript 对象,对共享内存执行原子操作。它设计为在多线程环境中使用,在该环境中,多个线程或 Web 工作人员可能同时访问和修改共享数据。
The Atomics object is a built-in JavaScript object that provides atomic operations on shared memory. It is designed to be used in a multi-threaded environment, where multiple threads or Web Workers may be concurrently accessing and modifying shared data.
The Essence of "Atomic"
在 Atomics 对象的上下文中,“原子”表示至关重要的特性:它执行本质上不可分割的操作。当我们将一项操作声明为原子操作时;我们暗示它的执行将像单一单元一样持续、不间断地发生。这种品质对于防止竞争条件至关重要;当并发操作的结果取决于它们的时序和执行顺序时,就会出现这种情况。
In the context of the Atomics object, "atomic" signifies a crucial characteristic: it performs operations that are inherently indivisible. When we declare an operation as atomic; we imply its execution occurs continuously and uninterruptedly like a single unit. This quality is indispensable in preventing race conditions; these arise when concurrent operations' outcomes depend on their timing and sequence of execution.
Atomic Operations
原子操作是在共享的内存上的低级操作,有保证能执行为一个独立、不可中断的单元。这些操作包括加法、减法、位运算、交换等。
Atomic operations are low-level operations on shared memory that are guaranteed to be executed as a single, uninterruptible unit. These operations include additions, subtractions, bitwise operations, exchanges, and more.
Atomics 对象提供了诸如 add、sub、and、or、xor、load、store、exchange 等方法,每个对应一个特定的原子操作。
The Atomics object provides methods like add, sub, and, or, xor, load, store, exchange, and others, each corresponding to a specific atomic operation.
Sr.No. |
Method & Description |
1 |
Atomics.add() Adds a specified value to the element at the specified index in the typed array. Returns the original value atomically. |
2 |
Atomics.sub() Subtracts a specified value from the element at the specified index in the typed array. Returns the original value atomically. |
3 |
Atomics.and() Performs an atomic bitwise AND operation on the element at the specified index in the typed array with the given value. Returns the original value atomically. |
4 |
Atomics.or() Performs an atomic bitwise OR operation on the element at the specified index in the typed array with the given value. Returns the original value atomically. |
5 |
Atomics.xor() Performs an atomic bitwise XOR operation on the element at the specified index in the typed array with the given value. Returns the original value atomically. |
6 |
Atomics.load() Retrieves the value at the specified index in the typed array atomically. |
7 |
Atomics.store() Stores the given value at the specified index in the typed array atomically. |
8 |
Atomics.exchange() Swaps the value at the specified index in the typed array with a specified value. Returns the original value atomically. |
9 |
Atomics. compareExchange() Compares the value at the specified index in the typed array with a provided expected value, and if they match, updates the value with a new value. Returns the original value atomically. |
10 |
Atomics.wait() Atomically waits for a value at the specified index in the typed array to be a specific value and then returns. Allows for efficient coordination between threads. |
11 |
Atomics.notify() Atomically notifies the wait queue associated with the specified index in the typed array. |
Examples
Example 1: Basic Usage of Atomics Operations
在本例中,针对共享内存上的基本原子操作演示了Atomics对象。这些操作包括加法、减法、按位AND运算、OR运算、XOR运算、加载、存储、交换和比较-交换值。每个操作确保了执行单元的不可分割性,这对于防止多线程环境中的竞争条件至关重要。
In this example, the Atomics object is demonstrated for its fundamental atomic operations on shared memory. These operations include addition, subtraction, bitwise AND, OR, XOR, loading, storing, exchanging, and compare-exchanging values. Each operation ensures the indivisibility of the executed unit, crucial for preventing race conditions in a multi-threaded environment.
Atomics.add()
Atomics.add()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.add()
const originalAddValue = Atomics.add(sharedArray, 0, 10);
console.log(`Atomics.add: Original value: ${originalAddValue}, New value: ${sharedArray[0]}`);
Atomics.add: Original value: 0, New value: 10
Atomics.add()
Atomics.add()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.sub()
const originalSubValue = Atomics.sub(sharedArray, 0, 5);
console.log(`Atomics.sub: Original value: ${originalSubValue}, New value: ${sharedArray[0]}`);
Atomics.sub: Original value: 10, New value: 5
Atomics.add()
Atomics.add()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.and()
const originalAndValue = Atomics.and(sharedArray, 0, 0b1010);
console.log(`Atomics.and: Original value: ${originalAndValue}, New value: ${sharedArray[0].toString(2)}`);
Atomics.and: Original value: 5, New value: 0
Atomics.or()
Atomics.or()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.or()
const originalOrValue = Atomics.or(sharedArray, 0, 0b1100);
console.log(`Atomics.or: Original value: ${originalOrValue}, New value: ${sharedArray[0].toString(2)}`);
Atomics.or: Original value: 0, New value: 1100
Atomics.xor()
Atomics.xor()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.xor()
const originalXorValue = Atomics.xor(sharedArray, 0, 0b0110);
console.log(`Atomics.xor: Original value: ${originalXorValue}, New value: ${sharedArray[0].toString(2)}`);
Atomics.xor: Original value: 12, New value: 1010
Atomics.load()
Atomics.load()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.load()
const loadedValue = Atomics.load(sharedArray, 0);
console.log(`Atomics.load: Loaded value: ${loadedValue}`);
Atomics.load: Loaded value: 10
Atomics.store()
Atomics.store()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.store()
Atomics.store(sharedArray, 0, 42);
console.log(`Atomics.store: New value: ${sharedArray[0]}`);
Atomics.store: New value: 42
Atomics.exchange()
Atomics.exchange()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.exchange()
const originalExchangeValue = Atomics.exchange(sharedArray, 0, 99);
console.log(`Atomics.exchange: Original value: ${originalExchangeValue}, New value: ${sharedArray[0]}`);
Atomics.exchange: Original value: 42, New value: 99
Atomics.compareExchange()
Atomics.compareExchange()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.compareExchange()
const expectedValue = 99;
const newValue = 55;
const successfulCompareExchange = Atomics.compareExchange(sharedArray, 0, expectedValue, newValue);
console.log(`Atomics.compareExchange: Operation was${successfulCompareExchange ? ' ' : ' not '}successful. New value: ${sharedArray[0]}`);
Atomics.compareExchange: Operation was successful. New value: 55
Atomics.wait()
Atomics.wait()
// Shared memory setup
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Atomics.wait()
const valueToWaitFor = 55;
Atomics.store(sharedArray, 0, valueToWaitFor);
setTimeout(() => {
Atomics.notify(sharedArray, 0);
}, 2000);
const waitResult = Atomics.wait(sharedArray, 0, valueToWaitFor, 5000);
console.log(`Atomics.wait: Wait result: ${waitResult}`);
Atomics.wait: Wait result: timed-out
Example 2: Real-World Use Case - Synchronized Counter
在这种实际场景中,我们使用 Atomics 对象来构建一个同步计数器;多个线程通过使用 Atomics.add() 操作来递增该计数器,从而保证更新过程中的原子性。这种应用程序显而易见地显示了有效线程协调的功能和必要性:它在多线程环境中提供实用的数据管理解决方案。
In this real-world scenario, we employ the Atomics object to construct a synchronized counter; multiple threads increment this counter through the use of the Atomics.add() operation, thus guaranteeing atomicity in our update process. The functionality and necessity for effective thread coordination become evident with such an application: it offers practical data management solutions within a multi-threaded environment.
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Synchronized counter
function incrementCounter() {
const incrementValue = 1;
const originalValue = Atomics.add(sharedArray, 0, incrementValue);
console.log(`Incremented counter by ${incrementValue}. New value: ${sharedArray[0]}`);
}
// Multiple threads incrementing the counter
setInterval(() => {
incrementCounter();
}, 1000);
// Simulate other activities in the main thread
setInterval(() => {
console.log('Main thread doing other work.');
}, 3000);
Incremented counter by 1. New value: 1
Incremented counter by 1. New value: 2
Main thread doing other work.
Incremented counter by 1. New value: 3
Incremented counter by 1. New value: 4
Incremented counter by 1. New value: 5
Main thread doing other work.
Incremented counter by 1. New value: 6
Incremented counter by 1. New value: 7
Incremented counter by 1. New value: 8
Main thread doing other work.
...