ES8 引入 Shared Memory,避免 Web Worker 下数据拷贝的性能损失

什么是 Shared Memory?

Shared Memory 是一种多进程间共享内存的机制。在 JavaScript 中,由于每个 Tab 或者每个 Worker 都有自己独立的 VM 实例,所以数据是不能直接共享的。

在 Web Worker 中,需要使用 postMessage() API 发送消息来传递数据。但当传递大量数据的时候,因为需要进行数据拷贝,会带来较大的性能损失。

ES8 引入的 Share Array Buffer 和 Atomics 可以让我们在多个 Worker 中共享内存,避免了数据拷贝,从而提高了性能。

Share Array Buffer

Share Array Buffer 是一种新的内存类型,在 JavaScript 引擎中分配连续内存块,可以存放不同类型的数据,如数字、字符串、对象、数组等。这些数据可以通过访问同一个内存地址来实现共享。

// 创建 Shared Array Buffer
const sab = new SharedArrayBuffer(8);

// 获取 ArrayBufferView
const view = new Int32Array(sab);

// 设置值
view[0] = 42;

// 在 Worker 中使用共享的 ArrayBufferView
worker.postMessage({view: view}, [view.buffer]);

在上述代码中,首先创建了一个大小为 8 字节的 ArrayBuffer,然后通过 Int32Array 获取了对应的 ArrayBufferView。接着,通过设置 view ArrayBufferView 中的值,将其传递到了一个 worker 中。

注意,当我们向 postMessage() 传递共享的 ArrayBufferView 时,我们需要将它转化为普通 ArrayBuffer,并以第二个参数的形式传递,这样就能让 worker 中得到这份内存的访问权。

Atomics

在多个 Worker 中共享同一个内存块,可能会产生协调和同步的问题。Atomics 负责解决这个问题。

Atomics 是一组可以原子性地操作共享内存的 API,支持原子操作的类型包括:整数(int32)、浮点数(float32、float64)和 64 位整数(Int64)。

const shmem = new SharedArrayBuffer(4);
const arr = new Int32Array(shmem);

// lock
Atomics.wait(arr, 0, 0);

// update value
arr[0]++;

// unlock
Atomics.notify(arr, 0, 1);

上述代码中,我们首先创建了一个长度为 4 的 ArrayBuffer,然后使用 Int32Array 获取了对应的 ArrayBufferView,最终使用了 Atomics API 执行了原子操作。

在 Atomics 中,wait() 用于获取锁,notify() 用于释放锁。wait() 的第一个参数是一个共享内存的 ArrayBufferView,第二个参数是要访问内存的索引位置,第三个参数是锁的值。如果锁的值不匹配,那么当前线程会被阻塞,直到锁被释放。notify() 的第二个参数是访问内存的索引位置,第三个参数是要释放的锁的数量。

总结

ES8 引入了 Shared Memory 这个新的特性,可以让我们在多个 Worker 中共享内存,避免了数据拷贝,从而提高了性能。在使用时,需要注意协调和同步的问题,这可以通过 Atomics API 来解决。

在实际应用中,我们可以使用 Shared Memory 来优化一些计算密集型的任务,例如视频编解码、图像处理等等。同时,共享内存也能够节省内存空间,避免不必要的资源浪费。

参考文献

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6594cbe6eb4cecbf2d90fc66


纠错反馈