Node.js v16.18.1 文档


目录

worker_threads 工作线程#

中英对照

稳定性: 2 - 稳定

源代码: lib/worker_threads.js

node:worker_threads 模块允许使用并行执行 JavaScript 的线程。 要访问它:

const worker = require('node:worker_threads');

工作线程对于执行 CPU 密集型的 JavaScript 操作很有用。 它们对 I/O 密集型的工作帮助不大。 Node.js 内置的异步 I/O 操作比工作线程更高效。

child_processcluster 不同,worker_threads 可以共享内存。 它们通过传输 ArrayBuffer 实例或共享 SharedArrayBuffer 实例来实现。

const {
  Worker, isMainThread, parentPort, workerData
} = require('node:worker_threads');

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script
      });
      worker.on('message', resolve);
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0)
          reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}

上面的示例为每个 parseJSAsync() 调用衍生工作线程。 在实践中,为这些类型的任务使用工作线程池。 否则,创建工作线程的开销可能会超过其收益。

当实现工作线程池时,使用 AsyncResource API 通知诊断工具(例如提供异步的堆栈跟踪)有关任务与其结果之间的相关性。 有关示例实现,请参阅 async_hooks 文档中的“将 AsyncResource 用于 Worker 线程池”

默认情况下,工作线程继承非进程特定的选项。 参考 Worker 构造函数选项 了解如何自定义工作线程选项,特别是 argvexecArgv 选项。

worker.getEnvironmentData(key)#

中英对照

  • key <any> 任何可以用作 <Map> 键的任意、可克隆的 JavaScript 值。
  • 返回: <any>

在工作线程中,worker.getEnvironmentData() 返回传给衍生线程的 worker.setEnvironmentData() 的数据的克隆。 每个新的 Worker 都会自动接收到自己的环境数据的副本。

const {
  Worker,
  isMainThread,
  setEnvironmentData,
  getEnvironmentData,
} = require('node:worker_threads');

if (isMainThread) {
  setEnvironmentData('Hello', 'World!');
  const worker = new Worker(__filename);
} else {
  console.log(getEnvironmentData('Hello'));  // 打印 'World!'。
}

worker.isMainThread#

中英对照

如果此代码不在 Worker 线程内运行,则为 true

const { Worker, isMainThread } = require('node:worker_threads');

if (isMainThread) {
  // 这会在工作线程实例中重新加载当前文件。
  new Worker(__filename);
} else {
  console.log('Inside Worker!');
  console.log(isMainThread);  // 打印 'false'。
}

worker.markAsUntransferable(object)#

中英对照

将对象标记为不可传输。 如果 object 出现在 port.postMessage() 调用的传输列表中,则忽略它。

特别是,这对于可以克隆而不是传输的对象,以及被发送方的其他对象使用的对象来说是有意义的。 例如,Node.js 用这个标记了它用于 BufferArrayBuffer

此操作无法撤消。

const { MessageChannel, markAsUntransferable } = require('node:worker_threads');

const pooledBuffer = new ArrayBuffer(8);
const typedArray1 = new Uint8Array(pooledBuffer);
const typedArray2 = new Float64Array(pooledBuffer);

markAsUntransferable(pooledBuffer);

const { port1 } = new MessageChannel();
port1.postMessage(typedArray1, [ typedArray1.buffer ]);

// 以下行打印 typedArray1 的内容,
// 它仍然拥有它的内存并且已经被克隆,而不是传输。
// 没有 `markAsUntransferable()`,这将打印空的 Uint8Array。
// typedArray2 也完好无损。
console.log(typedArray1);
console.log(typedArray2);

浏览器中没有与此 API 等效的 API。

worker.moveMessagePortToContext(port, contextifiedSandbox)#

中英对照

MessagePort 传输到不同的 vm 上下文 原始的 port 对象变得不可用,返回的 MessagePort 实例取而代之。

返回的 MessagePort 是目标上下文中的对象,并且继承自其全局的 Object 类。 传给 port.onmessage() 监听器的对象也在目标上下文中创建并且从其全局的 Object 类继承。

但是,创建的 MessagePort 不再继承 EventTarget,只有 port.onmessage() 可以使用它来接收事件。

worker.parentPort#

中英对照

如果此线程是 Worker,则这是允许与父线程通信的 MessagePort。 使用 parentPort.postMessage() 发送的消息在使用 worker.on('message') 的父线程中可用,使用 worker.postMessage() 从父线程发送的消息在使用 parentPort.on('message') 的该线程中可用。

const { Worker, isMainThread, parentPort } = require('node:worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename);
  worker.once('message', (message) => {
    console.log(message);  // 打印 'Hello, world!'。
  });
  worker.postMessage('Hello, world!');
} else {
  // 当收到来自父线程的消息时,则将其发回:
  parentPort.once('message', (message) => {
    parentPort.postMessage(message);
  });
}

worker.receiveMessageOnPort(port)#

中英对照

从给定的 MessagePort 接收消息。 如果没有消息可用,则返回 undefined,否则返回具有单个 message 属性的对象,该对象包含消息负载,对应于 MessagePort 队列中最旧的消息。

const { MessageChannel, receiveMessageOnPort } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
port1.postMessage({ hello: 'world' });

console.log(receiveMessageOnPort(port2));
// 打印: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// 打印: undefined

当使用此函数时,不会触发 'message' 事件,也不会调用 onmessage 监听器。

worker.resourceLimits#

中英对照

在这个工作线程中提供了一组 JS 引擎资源约束。 如果将 resourceLimits 选项传给 Worker 构造函数,则这与其值匹配。

如果在主线程中使用此,则其值为空对象。

worker.SHARE_ENV#

中英对照

可以作为 Worker 构造函数的 env 选项传入的特殊值,表示当前线程和工作线程应该共享对同一组环境变量的读写访问。

const { Worker, SHARE_ENV } = require('node:worker_threads');
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
  .on('exit', () => {
    console.log(process.env.SET_IN_WORKER);  // 打印 'foo'。
  });

worker.setEnvironmentData(key[, value])#

中英对照

  • key <any> 任何可以用作 <Map> 键的任意、可克隆的 JavaScript 值。
  • value <any> 任何任意的、可克隆的 JavaScript 值都将被克隆并自动传给所有新的 Worker 实例。 如果 value 作为 undefined 传入,则 key 之前设置的任何值都将被删除。

worker.setEnvironmentData() API 设置当前线程中 worker.getEnvironmentData() 的内容以及从当前上下文产生的所有新 Worker 实例。

worker.threadId#

中英对照

当前线程的整数标识符。 在对应的工作线程对象上(如果有的话),可以作为 worker.threadId 使用。 此值对于单个进程中的每个 Worker 实例都是唯一的。

worker.workerData#

中英对照

任意的 JavaScript 值,其中包含传给该线程的 Worker 构造函数的数据的克隆。

根据 HTML 结构化克隆算法,数据如同使用 postMessage() 一样被克隆。

const { Worker, isMainThread, workerData } = require('node:worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hello, world!' });
} else {
  console.log(workerData);  // 打印 'Hello, world!'。
}

继承自 EventTarget 的 BroadcastChannel 类#

中英对照

稳定性: 1 - 实验

BroadcastChannel 的实例允许与绑定到相同通道名称的所有其他 BroadcastChannel 实例进行异步的一对多通信。

'use strict';

const {
  isMainThread,
  BroadcastChannel,
  Worker
} = require('node:worker_threads');

const bc = new BroadcastChannel('hello');

if (isMainThread) {
  let c = 0;
  bc.onmessage = (event) => {
    console.log(event.data);
    if (++c === 10) bc.close();
  };
  for (let n = 0; n < 10; n++)
    new Worker(__filename);
} else {
  bc.postMessage('hello from every worker');
  bc.close();
}

new BroadcastChannel(name)#

中英对照

  • name <any> 要连接的通道名称。 任何可以使用 `${name}` 转换为字符串的 JavaScript 值都是允许的。

broadcastChannel.close()#

中英对照

关闭 BroadcastChannel 连接。

broadcastChannel.onmessage#

中英对照

  • 类型: <Function> 当接收到消息时,使用单个 MessageEvent 参数调用。

broadcastChannel.onmessageerror#

中英对照

  • 类型: <Function> 使用接收到的消息调用不能反序列化。

broadcastChannel.postMessage(message)#

中英对照

  • message <any> 任何可克隆的 JavaScript 值。

broadcastChannel.ref()#

中英对照

unref() 的相反。 如果它是唯一剩下的活动句柄(默认行为),则在先前 unref() 的 BroadcastChannel 上调用 ref() 不会让程序退出。 如果端口是 ref() 的,则再次调用 ref() 没有效果。

broadcastChannel.unref()#

中英对照

如果这是事件系统中唯一的活动句柄,则在广播通道上调用 unref() 允许线程退出。 如果广播通道已经 unref(),则再次调用 unref() 无效。

MessageChannel#

中英对照

worker.MessageChannel 类的实例代表异步的双向通信通道。 MessageChannel 没有自己的方法。 new MessageChannel() 产生具有 port1port2 属性的对象,其引用链接的 MessagePort 实例。

const { MessageChannel } = require('node:worker_threads');

const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });
// 从 `port1.on('message')` 监听器打印 received { foo: 'bar' }

MessagePort#

中英对照

worker.MessagePort 类的实例代表异步双向通信通道的一端。 它可以用来在不同的 Worker 之间传输结构化的数据、内存区域和其他 MessagePort

此实现匹配浏览器 MessagePort

'close' 事件#

中英对照

一旦通道的任一侧断开连接,则会触发 'close' 事件。

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

// 打印:
//   foobar
//   closed!
port2.on('message', (message) => console.log(message));
port2.on('close', () => console.log('closed!'));

port1.postMessage('foobar');
port1.close();

'message' 事件#

中英对照

为任何传入消息触发 'message' 事件,其中包含 port.postMessage() 的克隆输入。

此事件的监听器接收传给 postMessage()value 参数的副本,没有其他参数。

'messageerror' 事件#

中英对照

当反序列化消息失败时,则会触发 'messageerror' 事件。

目前,当在接收端实例化已发布的 JS 对象时发生错误时,则会触发此事件。 这种情况很少见,但可能会发生,例如,当某些 Node.js API 对象在 vm.Context 中接收到时(Node.js API 当前不可用)。

port.close()#

中英对照

禁止在连接的任一端进一步发送消息。 当此 MessagePort 上不会发生进一步的通信时,可以调用此方法。

'close' 事件在属于通道的两个 MessagePort 实例上触发。

port.postMessage(value[, transferList])#

中英对照

向该通道的接收端发送 JavaScript 值。 value 的传输方式与 HTML 结构化克隆算法兼容。

特别是与 JSON 的显着区别是:

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const circularData = {};
circularData.foo = circularData;
// 打印: { foo: [Circular] }
port2.postMessage(circularData);

transferList 可能是 ArrayBufferMessagePortFileHandle 对象的列表。 传输后,它们在通道的发送端不再可用(即使它们不包含在 value 中)。 与子进程不同,当前不支持传输句柄,例如网络套接字。

如果 value 包含 SharedArrayBuffer 实例,则可以从任一线程访问它们。 它们不能在 transferList 中列出。

value 可能仍然包含不在 transferList 中的 ArrayBuffer 实例;在这种情况下,底层内存被复制而不是移动。

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const uint8Array = new Uint8Array([ 1, 2, 3, 4 ]);
// 此发送 `uint8Array` 的副本:
port2.postMessage(uint8Array);
// 这不会复制数据,但会使 `uint8Array` 无法使用:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);

// `sharedUint8Array` 的内存
// 可以从 `.on('message')` 收到的原件和副本中访问:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);

// 这会将新创建的消息端口传输到接收器。
// 例如,这可用于在作为同一父线程的子线程的多个 `Worker` 线程之间
// 创建通信通道。
const otherChannel = new MessageChannel();
port2.postMessage({ port: otherChannel.port1 }, [ otherChannel.port1 ]);

消息对象立即克隆,发布后可修改,无副作用。

关于此 API 背后的序列化和反序列化机制的更多信息,请参见 node:v8 模块的序列化 API

传输 TypedArray 和 Buffer 时的注意事项#

中英对照

所有 TypedArrayBuffer 实例都是对底层 ArrayBuffer 的视图。 也就是说,实际存储原始数据的是 ArrayBuffer,而 TypedArrayBuffer 对象提供了查看和操作数据的方式。 在同一个 ArrayBuffer 实例上创建多个视图是可能且常见的。 使用传输列表传输 ArrayBuffer 时必须非常小心,因为这样做会导致共享同一个 ArrayBuffer 的所有 TypedArrayBuffer 实例变得不可用。

const ab = new ArrayBuffer(10);

const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);

console.log(u2.length);  // 打印 5

port.postMessage(u1, [u1.buffer]);

console.log(u2.length);  // 打印 0

对于 Buffer 实例,具体来说,底层 ArrayBuffer 是否可以被传输或克隆完全取决于实例是如何创建的,这通常无法可靠地确定。

ArrayBuffer 可以用 markAsUntransferable() 标记来表示它应该总是被克隆并且永远不会被传输。

根据 Buffer 实例的创建方式,它可能拥有也可能不拥有其底层 ArrayBuffer。 除非知道 Buffer 实例拥有它,否则不得传输 ArrayBuffer。 特别是,对于从内部 Buffer 池(使用,例如 Buffer.from()Buffer.allocUnsafe())创建的 Buffer,传输它们是不可能的,它们总是被克隆,这会发送整个 Buffer 池的副本。 此行为可能会带来意想不到的更高内存使用率和可能的安全问题。

有关 Buffer 池化的更多详细信息,请参阅 Buffer.allocUnsafe()

使用 Buffer.alloc()Buffer.allocUnsafeSlow() 创建的 Buffer 实例的 ArrayBuffer 始终可以传输,但这样做会使那些 ArrayBuffer 的所有其他现有视图无法使用。

使用原型、类和访问器克隆对象时的注意事项#

中英对照

因为对象克隆使用 HTML 结构化克隆算法,不可枚举的属性、属性访问器和对象原型不会被保留。 特别是,Buffer 对象将在接收方读取为普通 Uint8Array,并且 JavaScript 类的实例将被克隆为普通 JavaScript 对象。

const b = Symbol('b');

class Foo {
  #a = 1;
  constructor() {
    this[b] = 2;
    this.c = 3;
  }

  get d() { return 4; }
}

const { port1, port2 } = new MessageChannel();

port1.onmessage = ({ data }) => console.log(data);

port2.postMessage(new Foo());

// 打印: { c: 3 }

此限制扩展到许多内置对象,例如全局的 URL 对象:

const { port1, port2 } = new MessageChannel();

port1.onmessage = ({ data }) => console.log(data);

port2.postMessage(new URL('https://example.org'));

// 打印: { }

port.hasRef()#

中英对照

稳定性: 1 - 实验

如果为 true,则 MessagePort 对象将使 Node.js 事件循环保持活动状态。

port.ref()#

中英对照

unref() 的相反。 如果它是唯一剩下的活动句柄(默认行为),则在以前的 unref() 端口上调用 ref() 不会让程序退出。 如果端口是 ref() 的,则再次调用 ref() 没有效果。

如果使用 .on('message') 绑定或删除监听器,则根据事件的监听器是否存在,端口将自动进行 ref()unref()

port.start()#

中英对照

开始在此 MessagePort 上接收消息。 当将此端口用作事件触发器时,一旦绑定了 'message' 监听器,则会自动调用它

此方法与 Web MessagePort API 相同。 在 Node.js 中,只有在没有事件监听器时才用于忽略消息。 Node.js 在处理 .onmessage 方面也有分歧。 设置它会自动调用 .start(),但取消设置它会让消息排队,直到设置新的处理程序或端口被丢弃。

port.unref()#

中英对照

如果这是事件系统中唯一的活动句柄,则在端口上调用 unref() 允许线程退出。 如果端口已经 unref(),则再次调用 unref() 无效。

如果使用 .on('message') 绑定或删除监听器,则根据事件的监听器是否存在,端口将自动进行 ref()unref()

Worker#

中英对照

Worker 类代表独立的 JavaScript 执行线程。 大多数 Node.js API 都可以在其中使用。

工作线程环境中的显着差异是:

可以在其他 Worker 内部创建 Worker 实例。

网络工作线程node:cluster 模块一样,可以通过线程间消息传递来实现双向通信。 在内部,Worker 有一对内置的 MessagePort,在创建 Worker 时它们已经相互关联。 虽然父端的 MessagePort 对象没有直接暴露,但其功能通过父线程 Worker 对象上的 worker.postMessage()worker.on('message') 事件暴露。

要创建自定义的消息通道(鼓励使用默认的全局通道,因为它有助于分离关注点),用户可以在任一线程上创建 MessageChannel 对象,并通过预先存在的通道(例如全局通道)将该 MessageChannel 上的 MessagePort 之一传给另一个线程。

有关如何传递消息以及可以成功通过线程屏障传输的 JavaScript 值类型的更多信息,请参阅 port.postMessage()

const assert = require('node:assert');
const {
  Worker, MessageChannel, MessagePort, isMainThread, parentPort
} = require('node:worker_threads');
if (isMainThread) {
  const worker = new Worker(__filename);
  const subChannel = new MessageChannel();
  worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
  subChannel.port2.on('message', (value) => {
    console.log('received:', value);
  });
} else {
  parentPort.once('message', (value) => {
    assert(value.hereIsYourPort instanceof MessagePort);
    value.hereIsYourPort.postMessage('the worker is sending this');
    value.hereIsYourPort.close();
  });
}

new Worker(filename[, options])#

中英对照

  • filename <string> | <URL> 工作线程的主脚本或模块的路径。 必须是以 ./../ 开头的绝对路径或相对路径(即相对于当前工作目录)、或者是使用 file:data: 协议的 WHATWG URL 对象 当使用 data: 网址时,使用 ECMAScript 模块加载器根据 MIME 类型解释数据。 如果 options.evaltrue,则这是包含 JavaScript 代码(而不是路径)的字符串。
  • options <Object>
    • argv <any[]> 将被字符串化并附加到工作线程中的 process.argv 的参数列表。 这与 workerData 非常相似,但这些值在全局的 process.argv 上可用,就好像它们作为 CLI 选项传给脚本一样。
    • env <Object> 如果设置,则指定工作线程内 process.env 的初始值。 作为特殊值,worker.SHARE_ENV 可以用来指定父线程和子线程应该共享它们的环境变量;在这种情况下,对线程的 process.env 对象的更改也会影响另一个线程。 默认值: process.env
    • eval <boolean> 如果 true 并且第一个参数是 string,则将构造函数的第一个参数解释为一旦工作线程在线就执行的脚本。
    • execArgv <string[]> 传给工作线程的 node CLI 选项的列表。 不支持 V8 选项(如 --max-old-space-size)和影响进程的选项(如 --title)。 如果设置,则此在工作线程内部作为 process.execArgv 提供。 默认情况下,选项继承自父线程。
    • stdin <boolean> 如果设置为 true,则 worker.stdin 提供其内容在工作线程中显示为 process.stdin 的可写流。 默认情况下,不提供任何数据。
    • stdout <boolean> 如果设置为 true,则 worker.stdout 不会自动通过管道传输到父线程中的 process.stdout
    • stderr <boolean> 如果设置为 true,则 worker.stderr 不会自动通过管道传输到父线程中的 process.stderr
    • workerData <any> 任何被克隆并作为 require('node:worker_threads').workerData 可用的 JavaScript 值。 克隆按照 HTML 结构化克隆算法中的描述进行,如果无法克隆对象(例如,因为它包含 functions),则会抛出错误。
    • trackUnmanagedFds <boolean> 如果设置为 true,则工作线程会跟踪通过 fs.open()fs.close() 管理的原始文件描述符,并在工作线程退出时关闭它们,类似于网络套接字或通过 FileHandle API 管理的文件描述符等其他资源。 此选项会被所有嵌套的 Worker 自动继承。 默认值: true
    • transferList <Object[]> 如果在 workerData 中传入一个或多个类似 MessagePort 的对象,则这些条目需要 transferList 或抛出 ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST。 有关详细信息,请参阅 port.postMessage()
    • resourceLimits <Object> 新的 JS 引擎实例的一组可选资源限制。 达到这些限制会导致 Worker 实例终止。 这些限制只影响 JS 引擎,不影响外部数据,不包括 ArrayBuffer。 即使设置了这些限制,如果遇到全局内存不足的情况,进程仍可能会中止。
      • maxOldGenerationSizeMb <number> 主堆的最大大小 (以 MB 为单位)。 如果设置了命令行参数 --max-old-space-size,它将覆盖此设置。
      • maxYoungGenerationSizeMb <number> 最近创建的对象的最大堆空间大小。 如果设置了命令行参数 --max-semi-space-size,它将覆盖此设置。
      • codeRangeSizeMb <number> 用于生成代码的预分配内存范围的大小。
      • stackSizeMb <number> 线程的默认最大堆栈大小。 较小的值可能会导致工作线程实例无法使用。 默认值: 4

'error' 事件#

中英对照

如果工作线程抛出未捕获的异常,则会触发 'error' 事件。 在这种情况下,工作线程被终止。

'exit' 事件#

中英对照

一旦工作线程停止,则会触发 'exit' 事件。 如果工作线程是通过调用 process.exit() 退出的,则 exitCode 参数就是传入的退出码。 如果工作线程被终止,则 exitCode 参数为 1

这是任何 Worker 实例触发的最终事件。

'message' 事件#

中英对照

当工作线程调用 require('node:worker_threads').parentPort.postMessage() 时,则会触发 'message' 事件。 详情请见 port.on('message') 事件。

从工作线程发送的所有消息都在 Worker 对象上触发 'exit' 事件之前触发。

'messageerror' 事件#

中英对照

当反序列化消息失败时,则会触发 'messageerror' 事件。

'online' 事件#

中英对照

当工作线程开始执行 JavaScript 代码时,则会触发 'online' 事件。

worker.getHeapSnapshot()#

中英对照

  • 返回: <Promise> 对包含 V8 堆快照的可读流的 promise

返回工作线程当前状态的 V8 快照的可读流。 有关详细信息,请参阅 v8.getHeapSnapshot()

如果工作线程不再运行,这可能发生在 'exit' 事件触发之前,返回的 Promise 会立即使用 ERR_WORKER_NOT_RUNNING 错误拒绝。

worker.performance#

中英对照

可用于从工作线程实例查询性能信息的对象。 类似于perf_hooks.performance

performance.eventLoopUtilization([utilization1[, utilization2]])#

中英对照

perf_hooks eventLoopUtilization() 相同的调用,除了返回工作线程实例的值。

一个区别是,与主线程不同,工作线程内的引导是在事件循环内完成的。 因此,一旦工作线程的脚本开始执行,事件循环的利用率将立即可用。

不增加的 idle 时间并不表示工作线程卡在引导中。 下面的示例展示了工作线程的整个生命周期从未累积任何 idle 时间,但仍然能够处理消息。

const { Worker, isMainThread, parentPort } = require('node:worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename);
  setInterval(() => {
    worker.postMessage('hi');
    console.log(worker.performance.eventLoopUtilization());
  }, 100).unref();
  return;
}

parentPort.on('message', () => console.log('msg')).unref();
(function r(n) {
  if (--n < 0) return;
  const t = Date.now();
  while (Date.now() - t < 300);
  setImmediate(r, n);
})(10);

工作线程的事件循环利用率仅在 'online' 事件触发后可用,如果在此之前或在 'exit' 事件之后调用,则所有属性的值都为 0

worker.postMessage(value[, transferList])#

中英对照

向通过 require('node:worker_threads').parentPort.on('message') 接收到的工作线程发送消息。 有关详细信息,请参阅 port.postMessage()

worker.ref()#

中英对照

unref() 相反,如果它是唯一剩下的活动句柄(默认行为),则在以前的 unref() 的工作线程上调用 ref() 不会让程序退出。 如果工作线程是 ref() 的,则再次调用 ref() 没有效果。

worker.resourceLimits#

中英对照

为此工作线程提供了一组 JS 引擎资源约束。 如果将 resourceLimits 选项传给 Worker 构造函数,则这与其值匹配。

如果工作线程已经停止,则返回值是空对象。

worker.stderr#

中英对照

这是包含工作线程内写入 process.stderr 的数据的可读流。 如果 stderr: true 没有传给 Worker 构造函数,则数据将通过管道传输到父线程的 process.stderr 流。

worker.stdin#

中英对照

如果将 stdin: true 传给 Worker 构造函数,则这是可写流。 写入此流的数据将在工作线程中作为 process.stdin 可用。

worker.stdout#

中英对照

这是包含工作线程内写入 process.stdout 的数据的可读流。 如果 stdout: true 没有传给 Worker 构造函数,则数据将通过管道传输到父线程的 process.stdout 流。

worker.terminate()#

中英对照

尽快停止工作线程中的所有 JavaScript 执行。 返回在触发 'exit' 事件时履行退出码的 Promise。

worker.threadId#

中英对照

引用线程的整数标识符。 在工作线程内部,它作为 require('node:worker_threads').threadId 可用。 此值对于单个进程中的每个 Worker 实例都是唯一的。

worker.unref()#

中英对照

如果这是事件系统中唯一的活动句柄,则在工作线程上调用 unref() 允许线程退出。 如果工作线程已经 unref(),则再次调用 unref() 无效。

注意事项#

标准输入输出的同步阻塞#

中英对照

Worker 利用通过 <MessagePort> 传入的消息来实现与 stdio 的交互。 这意味着来自 Workerstdio 输出可能会被接收端的同步代码阻塞,这会阻塞 Node.js 事件循环。

import {
  Worker,
  isMainThread,
} from 'worker_threads';

if (isMainThread) {
  new Worker(new URL(import.meta.url));
  for (let n = 0; n < 1e10; n++) {
    // 循环模拟工作。
  }
} else {
  // 此输出将被主线程中的 for 循环阻塞。
  console.log('foo');
}'use strict';

const {
  Worker,
  isMainThread,
} = require('node:worker_threads');

if (isMainThread) {
  new Worker(__filename);
  for (let n = 0; n < 1e10; n++) {
    // 循环模拟工作。
  }
} else {
  // 此输出将被主线程中的 for 循环阻塞。
  console.log('foo');
}

从预加载脚本启动工作线程#

中英对照

从预加载脚本(使用 -r 命令行标志加载和运行的脚本)启动工作线程时要小心。 除非显式设置了 execArgv 选项,否则新的工作线程会自动从正在运行的进程继承命令行标志,并将预加载与主线程相同的预加载脚本。 如果预加载脚本无条件地启动工作线程,则每个衍生的线程都会衍生另一个直到应用程序崩溃。

返回顶部