Node.js 线程传二进制:复制和转移 ArrayBuffer 有什么区别
把大二进制数据交给 Worker 时,先确定发送方是否还要读取同一块内存。默认消息会复制普通 ArrayBuffer 的内容。将独占的 ArrayBuffer 加入 transfer list 可以转移其所有权,发送方随后不能继续使用该缓冲区以及它的其他视图。
1. 本机复现
保存为 worker_lab.mjs,运行 node worker_lab.mjs。同一个文件在主线程发消息,在工作线程把收到的字节转成普通数组返回。
import assert from 'node:assert/strict';
import { once } from 'node:events';
import { isMainThread, parentPort, Worker } from 'node:worker_threads';
if (!isMainThread) {
parentPort.on('message', bytes => parentPort.postMessage(Array.from(bytes)));
} else {
const worker = new Worker(new URL(import.meta.url));
try {
const copied = Uint8Array.of(1, 2, 3);
const copyResult = once(worker, 'message');
worker.postMessage(copied);
copied[0] = 9;
const [copy] = await copyResult;
assert.deepEqual(copy, [1, 2, 3]);
assert.equal(copied.byteLength, 3);
console.log('copy: received', copy.join(','), 'sender[0]=', copied[0]);
const moved = Uint8Array.of(4, 5, 6);
const alias = moved.subarray(1);
const moveResult = once(worker, 'message');
worker.postMessage(moved, [moved.buffer]);
assert.equal(moved.byteLength, 0);
assert.equal(alias.byteLength, 0);
const [received] = await moveResult;
assert.deepEqual(received, [4, 5, 6]);
console.log('transfer: received', received.join(','), 'sender lengths=',
moved.byteLength, alias.byteLength);
} finally {
await worker.terminate();
}
}
本地实测输出如下。
copy: received 1,2,3 sender[0]= 9
transfer: received 4,5,6 sender lengths= 0 0
2. 明确谁拥有底层缓冲区
subarray() 创建的是视图。即便它只覆盖原始数组的一部分,转移原数组的 buffer 后,这个视图也会失效。如果只想把切片给 Worker,可以先用 Uint8Array.from(view) 分配并复制这一段,再转移新数组的缓冲区。这个步骤仍有一次切片复制,开销取决于数据量。
Node.js 的 Buffer 可能引用内存池。Node 文档指出,Buffer.from()、Buffer.allocUnsafe() 等创建的实例如果来自池,其底层缓冲区不能作为独占内存交接,复制还可能涉及整个池。来源不明确时,为要发送的字节创建独立的普通 Uint8Array。只有当多个线程确实要并发访问同一份内存时,再考虑 SharedArrayBuffer 并设计同步机制。
小结
继续使用原数据就复制,能够交出独占底层内存就转移。发送前确认是否还有视图引用同一缓冲区。
数据来源与检索时间
检索时间 2026-11-13。
| 来源 | URL | 对应内容 |
|---|---|---|
| Node.js worker_threads | https://nodejs.org/docs/latest-v24.x/api/worker_threads.html#portpostmessagevalue-transferlist | 消息复制、转移列表及共享缓冲区 |
| Node.js TypedArray 和 Buffer | https://nodejs.org/docs/latest-v24.x/api/worker_threads.html#considerations-when-transferring-typedarrays-and-buffers | 共享视图失效与 Buffer 内存池 |
核验说明
- Windows、Node.js v24.19.0 在真实工作线程里验证复制快照、转移结果和两个视图失效。样本仅三字节,未测吞吐量,也未操作内存池中的 Buffer。