Node.js v18.18.2 文档


目录

工作线程#

稳定性:2 - 稳定

源代码: lib/worker_threads.js

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

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

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

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()调用生成一个工作线程。在实践中,使用工作人员池来完成此类任务。否则,创建 Workers 的开销可能会超过他们的收益。

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

默认情况下,工作线程继承非特定于进程的选项。请参阅 Worker constructor options了解如何自定义工作线程选项,特别是argvexecArgv选项。

worker.getEnvironmentData(key)#

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

在工作线程中,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'));  // Prints 'World!'.
} 

worker.isMainThread#

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

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

if (isMainThread) {
  // This re-loads the current file inside a Worker instance.
  new Worker(__filename);
} else {
  console.log('Inside Worker!');
  console.log(isMainThread);  // Prints 'false'.
} 

worker.markAsUntransferable(object)#

将对象标记为不可转移。如果object出现在port.postMessage()调用的转接列表中,则会被忽略。

特别是,这对于可以克隆而不是传输的对象以及由发送端的其他对象使用的对象来说是有意义的。例如,Node.js 使用此标记用于其 Buffer池的ArrayBuffer

此操作无法撤消。

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 ]);

// The following line prints the contents of typedArray1 -- it still owns
// its memory and has been cloned, not transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array.
// typedArray2 is intact as well.
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);  // Prints 'Hello, world!'.
  });
  worker.postMessage('Hello, world!');
} else {
  // When a message from the parent thread is received, send it back:
  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));
// Prints: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// Prints: undefined 

使用此函数时,不会发出 'message'事件,并且不会调用onmessage侦听器。

worker.resourceLimits#

在此 Worker 线程内提供 JS 引擎资源约束集。如果resourceLimits选项已传递给Worker构造函数,则它与其值匹配。

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

worker.SHARE_ENV#

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

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);  // Prints '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);  // Prints 'Hello, world!'.
} 

类:BroadcastChannel extends EventTarget#

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() ed BroadcastChannel上调用ref()不会让程序退出(默认行为)。如果端口是ref() ed,则再次调用ref()无效。

broadcastChannel.unref()#

如果这是事件系统中唯一的事件句柄,则在 BroadcastChannel 上调用unref()允许线程退出。如果 BroadcastChannel 已经是unref() ed,则再次调用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' });
// Prints: received { foo: 'bar' } from the `port1.on('message')` listener 

类:MessagePort#

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

此实现与浏览器MessagePort匹配。

事件:'close'#

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

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

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

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

事件:'message'#

  • value <any>传输的值

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

此事件的侦听器接收传递给postMessage()value 参数的克隆,并且没有其他参数。

事件:'messageerror'#

反序列化消息失败时会发出'messageerror'事件。

目前,当在接收端实例化发布的 JS 对象时发生错误时,会发出此事件。这种情况很少见,但可能会发生,例如,当在vm.Context中接收某些 Node.js API 对象时(其中 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;
// Prints: { 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 ]);
// This posts a copy of `uint8Array`:
port2.postMessage(uint8Array);
// This does not copy data, but renders `uint8Array` unusable:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);

// The memory for the `sharedUint8Array` is accessible from both the
// original and the copy received by `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);

// This transfers a freshly created message port to the receiver.
// This can be used, for example, to create communication channels between
// multiple `Worker` threads that are children of the same parent thread.
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);  // prints 5

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

console.log(u2.length);  // prints 0 

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

ArrayBuffer可以用markAsUntransferable()标记,以指示它应始终被克隆且从不转移。

根据Buffer实例的创建方式,它可能拥有也可能不拥有其底层的ArrayBuffer。除非知道Buffer实例拥有ArrayBuffer ,否则不得转让它。特别是,对于从内部 Buffer池创建的 Buffer(例如使用Buffer.from()Buffer.allocUnsafe()),传输它们不是可能,并且它们总是被克隆,这会发送整个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());

// Prints: { c: 3 } 

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

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

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

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

// Prints: { } 

port.hasRef()#

稳定性:1 - 实验性

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

port.ref()#

unref()相反。如果它是唯一剩余的事件句柄,则在之前的unref() ed 端口 上调用ref()不会让程序退出(默认行为)。如果端口是ref() ed,则再次调用ref()无效。

如果使用.on('message')添加或删除侦听器,则根据事件侦听器是否存在,会自动对端口进行ref()unref()编辑。

port.start()#

开始在此MessagePort上接收消息。当使用此端口作为事件发射器时,一旦附加了'message' 侦听器,就会自动调用此端口。

此方法的存在是为了与 Web MessagePort API 保持一致。在 Node.js 中,它仅适用于在不存在事件侦听器时忽略消息。Node.js 在处理.onmessage方面也有所不同。设置它会自动调用.start(),但取消设置它会让消息排队,直到设置新处​​理程序或丢弃端口。

port.unref()#

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

如果使用.on('message')添加或删除侦听器,则根据事件侦听器是否存在,端口会 自动进行 ref()unref()编辑。

类:Worker#

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

Worker 环境中的显着差异是:

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

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

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

有关如何传递消息以及可以通过线程屏障成功传输哪种 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 <字符串> | <URL> Worker 主脚本或模块的路径。必须是以./../开头的绝对路径或相对路径(即相对于当前工作目录) ,或者使用的WHATWG URL 对象file:data:协议。使用data: URL时,将使用ECMAScript 模块加载器根据 MIME 类型解释数据。如果options.evaltrue,则这是包含 JavaScript 代码而不是路径的字符串。
  • options <对象>
    • 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[]>传递给工作线程的节点 CLI 选项列表。不支持V8 选项(例如--max-old-space-size)和影响进程的选项(例如--title )。如果设置,则在工作线程内以process.execArgv形式提供。默认情况下,选项是从父线程继承的。
    • stdin <boolean>如果将此设置为true,则worker.stdin 提供一个可写流,其内容 在 Worker 内显示为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 结构化克隆算法中的描述进行,如果无法克隆对象(例如,因为它包含 function),则会抛出错误。
    • trackUnmanagedFds <boolean>如果设置为true ,则 Worker 跟踪通过fs.open()fs.close()管理的原始文件描述符,并关闭当 Worker 退出时,它们类似于通过FileHandle API 管理的网络套接字或文件描述符等其他资源。所有嵌套的Worker都会自动继承此选项。默认值: true
    • transferList <Object[]>如果在workerData中传递一个或多个类似MessagePort的对象,则这些项目需要transferList或抛出ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST请参阅port.postMessage()了解更多信息。
    • resourceLimits <Object>新 JS 引擎实例的一组可选资源限制。达到这些限制会导致Worker实例终止 。这些限制仅影响 JS 引擎,不会影响外部数据,包括任何ArrayBuffer。即使设置了这些限制,如果遇到全局内存不足的情况,进程仍然可能会中止。
    • name <string>可选的name附加到工作器标题以用于调试/识别目的,使最终标题为 [worker ${id}] ${name}默认值: ''

事件:'error'#

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

事件:'exit'#

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

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

事件:'message'#

  • value <any>传输的值

当工作线程调用 require('node:worker_threads').parentPort.postMessage()时,会发出'message'事件。请参阅port.on('message')事件了解更多详情。

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

事件:'messageerror'#

反序列化消息失败时会发出'messageerror'事件。

事件:'online'#

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

worker.getHeapSnapshot()#

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

返回 Worker 当前状态的 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() ed 工作线程 上调用 ref()不会让程序退出(默认行为)。如果工作线程已被ref()编辑,则再次调用ref()无效。

worker.resourceLimits#

为该Worker线程提供一组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() ed,则再次调用 unref()无效。

注意#

stdio的同步阻塞#

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++) {
    // Looping to simulate work.
  }
} else {
  // This output will be blocked by the for loop in the main thread.
  console.log('foo');
}'use strict';

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

if (isMainThread) {
  new Worker(__filename);
  for (let n = 0; n < 1e10; n++) {
    // Looping to simulate work.
  }
} else {
  // This output will be blocked by the for loop in the main thread.
  console.log('foo');
}

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

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

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org