- 断言测试
- 异步上下文跟踪
- 异步钩子
- 缓冲(Buffer)
- C++ 插件
- 使用 Node-API 的 C/C++ 插件
- C++ 嵌入 Node环境
- 子进程(Child processes)
- 集群(Cluster)
- 命令行选项
- 控制台(Console)
- 核心包(Corepack)
- 加密(Crypto)
- 调试器(Debugger)
- 已弃用的 API
- 诊断通道(Diagnostics Channel)
- 域名系统(DNS)
- 域(Domain)
- 错误(Errors)
- 事件(Events)
- 文件系统(File system)
- 全局变量(Globals)
- HTTP
- HTTP/2
- HTTPS
- 检查器(Inspector)
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:module
API - 模块:packages 模块
- 网络(Net)
- 系统(OS)
- 路径(Path)
- 性能挂钩(Performance hooks)
- 性能挂钩(Permissions)
- 进程(Process)
- Punycode 国际化域名编码
- 查询字符串(Query strings)
- 命令行库(Readline)
- REPL 交互式编程环境
- 诊断报告
- 单个可执行应用程序
- Stream 流
- 字符串解码器
- 单元测试
- 定时器(Timers)
- 传输层安全/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用程序
- V8
- 虚拟机
- WebAssembly
- Web加密 API(Web Crypto API)
- 网络流 API(Web Streams API)
- 工作线程(Worker threads)
- zlib
Node.js v18.18.2 文档
- Node.js v18.18.2
-
►
目录
- 工作线程
worker.getEnvironmentData(key)
worker.isMainThread
worker.markAsUntransferable(object)
worker.moveMessagePortToContext(port, contextifiedSandbox)
worker.parentPort
worker.receiveMessageOnPort(port)
worker.resourceLimits
worker.SHARE_ENV
worker.setEnvironmentData(key[, value])
worker.threadId
worker.workerData
- 类:
BroadcastChannel extends EventTarget
- Class:
MessageChannel
- Class:
MessagePort
- Class:
Worker
new Worker(filename[, options])
- Event:
'error'
- Event:
'exit'
- Event:
'message'
- Event:
'messageerror'
- Event:
'online'
worker.getHeapSnapshot()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.unref()
- Notes
- 工作线程
-
►
索引
- Assertion testing
- Asynchronous context tracking
- Async hooks
- Buffer
- C++ addons
- C/C++ addons with Node-API
- C++ embedder API
- Child processes
- Cluster
- Command-line options
- Console
- Corepack
- Crypto
- Debugger
- Deprecated APIs
- Diagnostics Channel
- DNS
- Domain
- Errors
- Events
- File system
- Globals
- HTTP
- HTTP/2
- HTTPS
- Inspector
- Internationalization
- Modules: CommonJS modules
- Modules: ECMAScript modules
- Modules:
node:module
API - Modules: Packages
- Net
- 系统(OS)
- 路径(Path)
- Performance hooks
- Permissions
- 进程(Process)
- Punycode
- Query strings
- 命令行库(Readline)
- REPL 交互式编程环境
- Report
- Single executable applications
- Stream
- String decoder
- Test runner
- Timers
- TLS/SSL
- Trace events
- TTY
- UDP/datagram
- URL
- Utilities
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- Worker threads
- Zlib
- ► 其他版本
- ► 选项
目录
- 工作线程
worker.getEnvironmentData(key)
worker.isMainThread
worker.markAsUntransferable(object)
worker.moveMessagePortToContext(port, contextifiedSandbox)
worker.parentPort
worker.receiveMessageOnPort(port)
worker.resourceLimits
worker.SHARE_ENV
worker.setEnvironmentData(key[, value])
worker.threadId
worker.workerData
- 类:
BroadcastChannel extends EventTarget
- 类:
MessageChannel
- 类:
MessagePort
- 类:
Worker
new Worker(filename[, options])
- 事件:
'error'
- 事件:
'exit'
- 事件:
'message'
- 事件:
'messageerror'
- 事件:
'online'
worker.getHeapSnapshot()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.unref()
- 注意
工作线程#
node:worker_threads
模块允许使用并行执行 JavaScript 的线程。要访问它:
const worker = require('node:worker_threads');
工作线程(线程)对于执行 CPU 密集型 JavaScript 操作非常有用。它们对于 I/O 密集型工作没有多大帮助。Node.js 内置的异步 I/O 操作比 Workers 更高效。
与child_process
或cluster
不同,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
了解如何自定义工作线程选项,特别是argv
和execArgv
选项。
worker.getEnvironmentData(key)
#
在工作线程中,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)
#
-
port
<MessagePort>要传输的消息端口。 -
返回:<消息端口>
将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()
生成一个具有port1
和port2
属性
的对象,这些属性引用链接的
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'
#
error
<Error>错误对象
反序列化消息失败时会发出'messageerror'
事件。
目前,当在接收端实例化发布的 JS 对象时发生错误时,会发出此事件。这种情况很少见,但可能会发生,例如,当在vm.Context
中接收某些 Node.js API 对象时(其中 Node.js API 目前不可用)。
port.close()
#
禁止在连接的任一侧进一步发送消息。当不再通过此MessagePort
进行进一步通信时,可以调用此方法
。
'close'
事件在属于通道的两个MessagePort
实例上发出。
port.postMessage(value[, transferList])
#
将 JavaScript 值发送到此通道的接收端。
value
以与HTML 结构化克隆算法兼容的方式传输。
特别是,与JSON
的显着差异是:
value
可能包含循环引用。value
可能包含内置 JS 类型的实例,例如RegExp
、BigInt
、Map
、Set
等value
可以包含类型化数组,均使用ArrayBuffer
和SharedArrayBuffer
。value
可能包含WebAssembly.Module
实例。value
不得包含以下本机(C++ 支持)对象:- <加密密钥> s,
- <文件句柄> s,
- <直方图> s,
- <KeyObject> s,
- <消息端口> s,
- <net.BlockList> s,
- <net.SocketAddress> es,
- <X509证书> s。
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
可以是ArrayBuffer
、MessagePort
和
FileHandle
对象的列表。传输后,它们在通道的发送端不再可用(即使它们不包含在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 时的注意事项#
所有TypedArray
和Buffer
实例都是底层
ArrayBuffer
的视图。也就是说,实际存储原始数据的是ArrayBuffer
,而TypedArray
和Buffer
对象提供查看和操作数据的方式。在同一个ArrayBuffer
实例上创建多个视图是可能且常见的。使用传输列表传输
ArrayBuffer
时必须非常小心,因为这样做会导致
共享同一ArrayBuffer
的所有TypedArray
和Buffer
实例变得不可用。
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()
#
- 返回:<布尔值>
如果为 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 环境中的显着差异是:
-
process.stdin
、process.stdout
和process.stderr
流可以由父线程重定向。 require('node:worker_threads').isMainThread
属性设置为false
。require('node:worker_threads').parentPort
消息端口可用。process.exit()
不会停止整个程序,只是停止单个线程,并且process.abort()
不可用。- 设置组或用户 ID 的
process.chdir()
和process
方法不可用。 - 除非另有指定,否则
process.env
是父线程环境变量的副本。对一份副本的更改在其他线程中不可见,对本机加载项也不可见(除非worker.SHARE_ENV
作为env
选项传递给Worker
构造函数)。 process.title
无法修改。- 信号不通过
process.on('...')
传递。 - 由于
调用
worker.terminate()
,执行可能会在任何时候停止。 - 无法访问来自父进程的 IPC 通道。
- 不支持
trace_events
模块。 - 本机附加组件只有在满足 某些条件时才能从多个线程加载。
可以在其他Worker
内创建Worker
实例。
与Web Workers和node: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 主脚本或模块的路径。必须是以./
或../
开头的绝对路径或相对路径(即相对于当前工作目录) ,或者使用的WHATWGURL
对象file:
或data:
协议。使用data:
URL时,将使用ECMAScript 模块加载器根据 MIME 类型解释数据。如果options.eval
为true
,则这是包含 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
。即使设置了这些限制,如果遇到全局内存不足的情况,进程仍然可能会中止。maxOldGenerationSizeMb
<number>主堆的最大大小(以 MB 为单位)。如果设置了命令行参数--max-old-space-size
,它将覆盖此设置。maxYoungGenerationSizeMb
<number>最近创建的对象的堆空间的最大大小。如果设置了命令行参数--max-semi-space-size
,它将覆盖此设置。codeRangeSizeMb
<number>用于生成代码的预分配内存范围的大小。stackSizeMb
<number>线程的默认最大堆栈大小。较小的值可能会导致 Worker 实例不可用。默认值:4
。
name
<string>可选的name
附加到工作器标题以用于调试/识别目的,使最终标题为[worker ${id}] ${name}
。默认值:''
。
事件:'error'
#
err
<错误>
如果工作线程抛出未捕获的异常,则会发出'error'
事件。在这种情况下,Worker将被解雇。
事件:'exit'
#
exitCode
<整数>
一旦工作线程停止,就会发出'exit'
事件。如果工作线程通过调用process.exit()
退出,则exitCode
参数是传递的退出代码。如果工作线程被终止,则exitCode
参数为
1
。
这是任何Worker
实例发出的最终事件。
事件:'message'
#
value
<any>传输的值
当工作线程调用
require('node:worker_threads').parentPort.postMessage()
时,会发出'message'
事件。请参阅port.on('message')
事件了解更多详情。
从工作线程发送的所有消息都会
在Worker
对象上发出'exit'
事件之前发出。
事件:'messageerror'
#
error
<Error>错误对象
反序列化消息失败时会发出'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]])
#
utilization1
<Object>先前调用eventLoopUtilization()
的结果。utilization2
<Object>在utilization1
之前调用eventLoopUtilization()
的结果 。- 返回<对象>
与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()
#
- 返回:< Promise >
尽快停止工作线程中的所有 JavaScript 执行。返回发出'exit'
事件时完成的退出代码的 Promise
。
worker.threadId
#
所引用线程的整数标识符。在工作线程内,它可以作为require('node:worker_threads').threadId
使用。该值对于单个进程内的每个Worker
实例都是唯一的。
worker.unref()
#
如果这是事件系统中唯一的事件句柄,则在工作线程上调用unref()
允许线程退出。如果工作线程已经unref()
ed,则再次调用
unref()
无效。
注意#
stdio的同步阻塞#
Worker
利用通过<MessagePort>传递的消息来实现与stdio
的交互。这意味着源自Worker
的stdio
输出可能会被接收端阻止 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
选项,否则新的工作线程会自动从正在运行的进程继承命令行标志,并预加载与主线程相同的预加载脚本。如果预加载脚本无条件启动工作线程,则生成的每个线程都会生成另一个线程,直到应用程序崩溃。