Worker threads
[Stable: 2 - Stable]
Stable: 2 Stability: 2 - 安定
ソースコード: lib/worker_threads.js
node:worker_threads モジュールは、JavaScript を並列に実行するスレッドの使用を可能にします。 それにアクセスするには:
const worker = require('node:worker_threads');ワーカー(スレッド)は、CPU 負荷の高い JavaScript 操作を実行するのに役立ちます。 I/O 負荷の高い作業にはあまり役立ちません。 Node.js の組み込みの非同期 I/O 操作は、ワーカーよりも効率的です。
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() の呼び出しごとにワーカースレッドを生成します。 実際には、これらの種類のタスクにはワーカーのプールを使用します。 そうしないと、ワーカーの作成のオーバーヘッドが、そのメリットを上回る可能性があります。
ワーカープールを実装する場合は、AsyncResource API を使用して、タスクとその結果の間の相関関係について診断ツール (たとえば、非同期スタックトレースを提供するため) に通知します。 実装例については、async_hooks ドキュメントの "Worker スレッドプールに AsyncResource を使用する" を参照してください。
ワーカースレッドは、デフォルトでプロセス固有でないオプションを継承します。 ワーカースレッドのオプション、特に argv および execArgv オプションをカスタマイズする方法については、Worker コンストラクターオプション を参照してください。
worker.getEnvironmentData(key)
[履歴]
| バージョン | 変更 |
|---|---|
| v17.5.0, v16.15.0 | 実験的ではなくなりました。 |
| v15.12.0, v14.18.0 | 追加: v15.12.0, v14.18.0 |
ワーカー スレッド内では、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
追加: v10.5.0
このコードが 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)
追加: v14.5.0, v12.19.0
object<any> 任意の JavaScript 値。
オブジェクトを転送不可としてマークします。object が port.postMessage() 呼び出しの転送リストに出現する場合、エラーがスローされます。object がプリミティブ値の場合、これは何もしません。
特に、これは、転送されるのではなく、複製できるオブジェクト、および送信側の他のオブジェクトで使用されるオブジェクトに適しています。たとえば、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();
try {
// This will throw an error, because pooledBuffer is not transferable.
port1.postMessage(typedArray1, [ typedArray1.buffer ]);
} catch (error) {
// error.name === 'DataCloneError'
}
// The following line prints the contents of typedArray1 -- it still owns
// its memory and has not been transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array and the
// postMessage call would have succeeded.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2);ブラウザには、これに相当する API はありません。
worker.isMarkedAsUntransferable(object)
追加: v21.0.0
オブジェクトが markAsUntransferable() で譲渡不可能としてマークされているかどうかを確認します。
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads');
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // trueを返します。このAPIに相当するものはブラウザーにはありません。
worker.markAsUncloneable(object)
追加: v23.0.0
object<any> 任意のJavaScript値。
オブジェクトを複製不可能としてマークします。object が port.postMessage() 呼び出しで message として使用された場合、エラーがスローされます。object がプリミティブ値の場合、これはnoopです。
これは ArrayBuffer、または Buffer のようなオブジェクトには影響しません。
この操作は元に戻すことはできません。
const { markAsUncloneable } = require('node:worker_threads');
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// anyObjectは複製不可能であるため、これはエラーをスローします。
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}このAPIに相当するものはブラウザーにはありません。
worker.moveMessagePortToContext(port, contextifiedSandbox)
追加: v11.13.0
port<MessagePort> 転送するメッセージポート。contextifiedSandbox<Object>vm.createContext()メソッドによって返される コンテキスト化 オブジェクト。- 戻り値: <MessagePort>
MessagePort を別の vm コンテキストに転送します。元の port オブジェクトは使用不能になり、返された MessagePort インスタンスがその代わりになります。
返された MessagePort はターゲットコンテキスト内のオブジェクトであり、そのグローバル Object クラスから継承します。port.onmessage() リスナーに渡されるオブジェクトもターゲットコンテキストで作成され、そのグローバル Object クラスから継承します。
ただし、作成された MessagePort は EventTarget から継承しなくなり、port.onmessage() のみを使用してイベントを受信できます。
worker.parentPort
追加: v10.5.0
このスレッドが 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.postMessageToThread(threadId, value[, transferList][, timeout])
追加: v22.5.0
[Stable: 1 - 実験的]
Stable: 1 Stability: 1.1 - 活発な開発
threadId<number> ターゲットのスレッドID。スレッドIDが無効な場合、ERR_WORKER_MESSAGING_FAILEDエラーがスローされます。ターゲットのスレッドIDが現在のスレッドIDと同じ場合、ERR_WORKER_MESSAGING_SAME_THREADエラーがスローされます。value<any> 送信する値。transferList<Object[]> 1つ以上のMessagePortのようなオブジェクトがvalueで渡される場合、それらのアイテムにはtransferListが必要です。そうでない場合、ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LISTがスローされます。詳細については、port.postMessage()を参照してください。timeout<number> メッセージが配信されるまで待機する時間(ミリ秒単位)。デフォルトはundefinedで、これは永遠に待機することを意味します。操作がタイムアウトした場合、ERR_WORKER_MESSAGING_TIMEOUTエラーがスローされます。- 戻り値: <Promise> メッセージが宛先スレッドによって正常に処理された場合に解決されるPromise。
スレッドIDで識別される別のワーカーに値を送信します。
ターゲットスレッドが workerMessage イベントのリスナーを持っていない場合、操作は ERR_WORKER_MESSAGING_FAILED エラーをスローします。
ターゲットスレッドが workerMessage イベントの処理中にエラーをスローした場合、操作は ERR_WORKER_MESSAGING_ERRORED エラーをスローします。
このメソッドは、ターゲットスレッドが現在のスレッドの直接の親または子ではない場合に使用する必要があります。2つのスレッドが親子関係にある場合は、require('node:worker_threads').parentPort.postMessage() および worker.postMessage() を使用してスレッドに通信させます。
以下の例は、postMessageToThread の使用を示しています。これは10個のネストされたスレッドを作成し、最後のスレッドがメインスレッドと通信しようとします。
import { fileURLToPath } from 'node:url';
import process from 'node:process';
import {
postMessageToThread,
threadId,
workerData,
Worker,
} from 'node:worker_threads';
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(fileURLToPath(import.meta.url), {
workerData: { level: level + 1 },
});
}
if (level === 0) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
postMessageToThread(source, { message: 'pong' });
});
} else if (level === 10) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
channel.postMessage('done');
channel.close();
});
await postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;const {
postMessageToThread,
threadId,
workerData,
Worker,
} = require('node:worker_threads');
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(__filename, {
workerData: { level: level + 1 },
});
}
if (level === 0) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
postMessageToThread(source, { message: 'pong' });
});
} else if (level === 10) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
channel.postMessage('done');
channel.close();
});
postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;worker.receiveMessageOnPort(port)
[履歴]
| バージョン | 変更 |
|---|---|
| v15.12.0 | port 引数は BroadcastChannel を参照できるようになりました。 |
| v12.3.0 | 追加: v12.3.0 |
port<MessagePort> | <BroadcastChannel>- 戻り値: <Object> | <undefined>
指定された MessagePort から単一のメッセージを受信します。メッセージがない場合、undefined が返されます。それ以外の場合は、message プロパティを1つだけ持つオブジェクトが返されます。このプロパティには、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
追加: v13.2.0, v12.16.0
この Worker スレッド内の JS エンジンのリソース制約のセットを提供します。resourceLimits オプションが Worker コンストラクタに渡された場合、これはその値と一致します。
これがメインスレッドで使用されている場合、その値は空のオブジェクトです。
worker.SHARE_ENV
追加: v11.14.0
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); // 'foo' と出力されます。
});worker.setEnvironmentData(key[, value])
[履歴]
| バージョン | 変更 |
|---|---|
| v17.5.0, v16.15.0 | 実験的ではなくなりました。 |
| v15.12.0, v14.18.0 | 追加: v15.12.0, v14.18.0 |
key<any> <Map> キーとして使用できる任意のクローン可能な JavaScript 値。value<any> 任意のクローン可能な JavaScript 値。クローンされ、すべての新しいWorkerインスタンスに自動的に渡されます。valueがundefinedとして渡された場合、keyに対して以前に設定された値は削除されます。
worker.setEnvironmentData() API は、現在のスレッドと、現在のコンテキストから生成されたすべての新しい Worker インスタンスで worker.getEnvironmentData() の内容を設定します。
worker.threadId
追加: v10.5.0
現在のスレッドの整数識別子。 対応する worker オブジェクト(もしあれば)では、worker.threadId として利用できます。 この値は、単一のプロセス内の各 Worker インスタンスに対して一意です。
worker.workerData
追加: v10.5.0
このスレッドの Worker コンストラクターに渡されたデータのクローンを含む任意の JavaScript 値。
データは、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!' と出力。
}Class: BroadcastChannel extends EventTarget
[履歴]
| バージョン | 変更点 |
|---|---|
| v18.0.0 | 実験的ではなくなりました。 |
| v15.4.0 | 追加: v15.4.0 |
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)
追加: v15.4.0
name<any> 接続するチャネルの名前。${name}を使用して文字列に変換できる JavaScript 値はすべて許可されます。
broadcastChannel.close()
追加: v15.4.0
BroadcastChannel 接続を閉じます。
broadcastChannel.onmessage
追加: v15.4.0
- Type: <Function> メッセージを受信すると、単一の
MessageEvent引数で呼び出されます。
broadcastChannel.onmessageerror
追加: v15.4.0
- タイプ: <Function> 受信したメッセージがデシリアライズできない場合に呼び出されます。
broadcastChannel.postMessage(message)
追加: v15.4.0
message<any> クローン可能な JavaScript 値。
broadcastChannel.ref()
追加: v15.4.0
unref() の反対です。以前に unref() された BroadcastChannel で ref() を呼び出しても、それが残された唯一のアクティブなハンドルである場合、プログラムは終了しません(デフォルトの動作)。ポートが ref() されている場合、再度 ref() を呼び出しても効果はありません。
broadcastChannel.unref()
追加: v15.4.0
BroadcastChannel で unref() を呼び出すと、これがイベントシステム内の唯一のアクティブなハンドルである場合に、スレッドが終了できます。BroadcastChannel が既に unref() されている場合、再度 unref() を呼び出しても効果はありません。
クラス: MessageChannel
追加: v10.5.0
worker.MessageChannel クラスのインスタンスは、非同期の双方向通信チャネルを表します。MessageChannel 自体にはメソッドはありません。new MessageChannel() は、リンクされた MessagePort インスタンスを参照する port1 および port2 プロパティを持つオブジェクトを生成します。
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
[履歴]
| バージョン | 変更点 |
|---|---|
| v14.7.0 | このクラスは EventEmitter からではなく、EventTarget から継承するようになりました。 |
| v10.5.0 | 追加: v10.5.0 |
- 継承: <EventTarget>
worker.MessagePort クラスのインスタンスは、非同期の双方向通信チャネルの一端を表します。構造化データ、メモリ領域、および他の MessagePort を異なる Worker 間で転送するために使用できます。
この実装は、ブラウザの MessagePort と一致します。
イベント: 'close'
追加: v10.5.0
チャネルのどちらかの側が切断されると、'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'
追加: v10.5.0
value<any> 送信された値
'message' イベントは、port.postMessage() のクローンされた入力を含む、すべての受信メッセージに対して発生します。
このイベントのリスナーは、postMessage() に渡された value パラメーターのクローンを受け取り、それ以上の引数は受け取りません。
イベント: 'messageerror'
追加: v14.5.0, v12.19.0
error<Error> エラーオブジェクト
メッセージのデシリアライズに失敗した場合、'messageerror' イベントが発生します。
現在、このイベントは、投稿されたJSオブジェクトを受信側でインスタンス化する際にエラーが発生した場合に発生します。 このような状況はまれですが、たとえば、特定のNode.js APIオブジェクトがvm.Contextで受信された場合(Node.js APIは現在利用できません)に発生する可能性があります。
port.close()
追加: v10.5.0
接続の両側でのメッセージのさらなる送信を無効にします。 このメソッドは、この MessagePort を介したこれ以上の通信が行われない場合に呼び出すことができます。
'close' イベント は、チャネルの一部である両方の MessagePort インスタンスで発生します。
port.postMessage(value[, transferList])
[履歴]
| バージョン | 変更点 |
|---|---|
| v21.0.0 | 転送できないオブジェクトが転送リストにある場合にエラーがスローされます。 |
| v15.6.0 | クローン可能な型のリストに X509Certificate を追加しました。 |
| v15.0.0 | クローン可能な型のリストに CryptoKey を追加しました。 |
| v15.14.0, v14.18.0 | クローン可能な型のリストに 'BlockList' を追加します。 |
| v15.9.0, v14.18.0 | クローン可能な型のリストに 'Histogram' 型を追加します。 |
| v14.5.0, v12.19.0 | クローン可能な型のリストに KeyObject を追加しました。 |
| v14.5.0, v12.19.0 | 転送可能な型のリストに FileHandle を追加しました。 |
| v10.5.0 | 追加: v10.5.0 |
value<any>transferList<Object[]>
JavaScriptの値をこのチャネルの受信側に送信します。 value は、HTML構造化クローンアルゴリズムと互換性のある方法で転送されます。
特に、JSON との重要な違いは次のとおりです。
valueは循環参照を含む場合があります。valueは、RegExp、BigInt、Map、Setなどの組み込み JS 型のインスタンスを含む場合があります。valueは、ArrayBufferとSharedArrayBufferの両方を使用する型付き配列を含む場合があります。valueは、WebAssembly.Moduleインスタンスを含む場合があります。valueは、次のネイティブ(C++ ベース)オブジェクト以外は含むことができません。
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 は、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 ]);
// これは `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 を転送する際の考慮事項
すべての 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); // 5 と出力
port.postMessage(u1, [u1.buffer]);
console.log(u2.length); // 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()
追加: v18.1.0, v16.17.0
- 戻り値: <boolean>
true の場合、MessagePort オブジェクトは Node.js イベントループをアクティブに保ちます。
port.ref()
追加: v10.5.0
unref() の反対です。 以前に unref() されたポートで ref() を呼び出しても、残りのアクティブなハンドルがそれだけの場合、プログラムは終了しません(デフォルトの動作)。 ポートが ref() されている場合、ref() を再度呼び出しても効果はありません。
.on('message') を使用してリスナーがアタッチまたは削除される場合、イベントのリスナーが存在するかどうかに応じて、ポートは自動的に ref() および unref() されます。
port.start()
Added in: v10.5.0
このMessagePortでメッセージの受信を開始します。このポートをイベントエミッターとして使用する場合、'message'リスナーがアタッチされると、これは自動的に呼び出されます。
このメソッドは、Web MessagePort APIとのパリティのために存在します。Node.jsでは、イベントリスナーが存在しない場合にメッセージを無視する場合にのみ役立ちます。Node.jsは、.onmessageの処理も異なります。それを設定すると、自動的に.start()が呼び出されますが、設定を解除すると、新しいハンドラーが設定されるか、ポートが破棄されるまでメッセージがキューに格納されます。
port.unref()
Added in: v10.5.0
ポートでunref()を呼び出すと、これがイベントシステムで唯一のアクティブなハンドルである場合、スレッドは終了できます。ポートが既にunref()されている場合、再度unref()を呼び出しても効果はありません。
.on('message')を使用してリスナーがアタッチまたは削除される場合、イベントのリスナーが存在するかどうかに応じて、ポートは自動的にref()およびunref()されます。
Class: Worker
Added in: v10.5.0
- 継承元: <EventEmitter>
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()は利用できません。process.chdir()およびグループまたはユーザーIDを設定するprocessメソッドは利用できません。process.envは、特に指定がない限り、親スレッドの環境変数のコピーです。1つのコピーへの変更は他のスレッドでは表示されず、ネイティブアドオンにも表示されません(worker.SHARE_ENVがWorkerコンストラクターへのenvオプションとして渡されない限り)。Windowsでは、メインスレッドとは異なり、環境変数のコピーは大文字と小文字を区別して動作します。process.titleは変更できません。- シグナルは、
process.on('...')を介して配信されません。 - 実行は、
worker.terminate()が呼び出された結果として、いつでも停止する可能性があります。 - 親プロセスからのIPCチャネルにはアクセスできません。
trace_eventsモジュールはサポートされていません。- ネイティブアドオンは、特定の条件を満たす場合にのみ、複数のスレッドからロードできます。
他のWorker内でWorkerインスタンスを作成できます。
Web Workersやnode:clusterモジュールと同様に、スレッド間メッセージパッシングを通じて双方向通信を実現できます。内部的には、Workerには、Workerの作成時にすでにお互いに関連付けられているMessagePortの組み込みペアがあります。親側のMessagePortオブジェクトは直接公開されていませんが、その機能はworker.postMessage()および親スレッドのWorkerオブジェクトのworker.on('message')イベントを介して公開されます。
カスタムメッセージングチャネルを作成するために(これは、関心の分離を促進するため、デフォルトのグローバルチャネルを使用するよりも推奨されます)、ユーザーはどちらかのスレッドでMessageChannelオブジェクトを作成し、既存のチャネル(グローバルチャネルなど)を介してMessageChannelのMessagePortの1つを他のスレッドに渡すことができます。
メッセージがどのように渡されるか、およびどの種類の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])
[履歴]
| バージョン | 変更点 |
|---|---|
| v19.8.0, v18.16.0 | デバッグのためにworkerタイトルに名前を追加できるnameオプションのサポートを追加しました。 |
| v14.9.0 | filename パラメーターは、data: プロトコルを使用する WHATWG URL オブジェクトにすることができます。 |
| v14.9.0 | trackUnmanagedFds オプションは、デフォルトで true に設定されました。 |
| v14.6.0, v12.19.0 | trackUnmanagedFds オプションが導入されました。 |
| v13.13.0, v12.17.0 | transferList オプションが導入されました。 |
| v13.12.0, v12.17.0 | filename パラメーターは、file: プロトコルを使用する WHATWG URL オブジェクトにすることができます。 |
| v13.4.0, v12.16.0 | argv オプションが導入されました。 |
| v13.2.0, v12.16.0 | resourceLimits オプションが導入されました。 |
| v10.5.0 | v10.5.0 で追加されました。 |
filename<string> | <URL> Worker のメインスクリプトまたはモジュールへのパス。絶対パスまたは相対パス(つまり、現在の作業ディレクトリからの相対パス)であり、./または../で始まるか、file:またはdata:プロトコルを使用する WHATWGURLオブジェクトである必要があります。data:URL を使用する場合、データは ECMAScript モジュールローダー を使用して MIME タイプに基づいて解釈されます。options.evalがtrueの場合、これはパスではなく JavaScript コードを含む文字列です。options<Object>argv<any[]> workerで文字列化され、process.argvに追加される引数のリスト。 これは主にworkerDataに似ていますが、値はスクリプトにCLIオプションとして渡されたかのように、グローバルprocess.argvで利用できます。env<Object> 設定されている場合、Worker スレッド内のprocess.envの初期値を指定します。特別な値として、親スレッドと子スレッドがそれらの環境変数を共有するように指定するために、worker.SHARE_ENVを使用できます。その場合、一方のスレッドのprocess.envオブジェクトへの変更は、他方のスレッドにも影響します。デフォルト:process.env。eval<boolean>trueであり、最初の引数がstringである場合、コンストラクターへの最初の引数を、worker がオンラインになったときに一度実行されるスクリプトとして解釈します。execArgv<string[]> worker に渡される node CLI オプションのリスト。V8 オプション(--max-old-space-sizeなど)およびプロセスに影響を与えるオプション(--titleなど)はサポートされていません。設定されている場合、これは worker 内で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()を介して管理される生のファイル記述子を追跡し、FileHandleAPI を介して管理されるネットワークソケットやファイル記述子などの他のリソースと同様に、Worker が終了するとそれらを閉じます。このオプションは、すべてのネストされたWorkerに自動的に継承されます。デフォルト:true。transferList<Object[]> 1つ以上のMessagePortのようなオブジェクトがworkerDataで渡される場合、それらのアイテムには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> デバッグ/識別の目的で worker タイトルに追加されるオプションのname。最終的なタイトルは[worker ${id}] ${name}になります。デフォルト:''。
イベント: 'error'
追加: v10.5.0
err<Error>
'error' イベントは、ワーカースレッドがキャッチされない例外をスローした場合に発生します。その場合、ワーカーは終了します。
イベント: 'exit'
追加: v10.5.0
exitCode<integer>
'exit' イベントは、ワーカーが停止したときに発生します。ワーカーが process.exit() を呼び出して終了した場合、exitCode パラメーターは渡された終了コードです。ワーカーが強制終了された場合、exitCode パラメーターは 1 です。
これは、すべての Worker インスタンスによって発生する最後のイベントです。
イベント: 'message'
追加: v10.5.0
value<any> 伝送された値
'message' イベントは、ワーカースレッドが require('node:worker_threads').parentPort.postMessage() を呼び出したときに発生します。詳細については、port.on('message') イベントを参照してください。
ワーカースレッドから送信されたすべてのメッセージは、'exit' イベント が Worker オブジェクトで発生する前に発生します。
イベント: 'messageerror'
追加: v14.5.0, v12.19.0
error<Error> Errorオブジェクト
'messageerror' イベントは、メッセージのデシリアライズに失敗した場合に発生します。
イベント: 'online'
追加: v10.5.0
'online' イベントは、ワーカースレッドが JavaScript コードの実行を開始したときに発生します。
worker.getHeapSnapshot([options])
[履歴]
| バージョン | 変更 |
|---|---|
| v19.1.0 | ヒープスナップショットを構成するためのオプションをサポートします。 |
| v13.9.0, v12.17.0 | 追加: v13.9.0, v12.17.0 |
Workerの現在の状態のV8スナップショットのreadable streamを返します。詳細については、v8.getHeapSnapshot()を参照してください。
Workerスレッドがすでに実行されていない場合('exit' イベントが発生する前に発生する可能性があります)、返されたPromiseはERR_WORKER_NOT_RUNNING エラーですぐに拒否されます。
worker.performance
追加: v15.1.0, v14.17.0, v12.22.0
ワーカーインスタンスからパフォーマンス情報をクエリするために使用できるオブジェクト。 perf_hooks.performance と同様です。
performance.eventLoopUtilization([utilization1[, utilization2]])
追加: v15.1.0, v14.17.0, v12.22.0
utilization1<Object>eventLoopUtilization()の以前の呼び出しの結果。utilization2<Object>utilization1より前のeventLoopUtilization()の以前の呼び出しの結果。- 戻り値: <Object>
perf_hooks eventLoopUtilization() と同じ呼び出しですが、ワーカーインスタンスの値が返される点が異なります。
1 つの違いは、メインスレッドとは異なり、ワーカー内のブートストラップはイベントループ内で行われることです。 そのため、ワーカーのスクリプトが実行を開始するとすぐに、イベントループの使用率が利用可能になります。
増加しない 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])
Added in: v10.5.0
value<any>transferList<Object[]>
require('node:worker_threads').parentPort.on('message') 経由で受信されるメッセージをワーカーに送信します。詳細については、port.postMessage() を参照してください。
worker.ref()
Added in: v10.5.0
unref() の反対です。以前に unref() されたワーカーで ref() を呼び出しても、それが唯一のアクティブなハンドルである場合、プログラムは終了しません (デフォルトの動作)。ワーカーが ref() されている場合、ref() を再度呼び出しても効果はありません。
worker.resourceLimits
Added in: v13.2.0, v12.16.0
この Worker スレッドの JS エンジンリソース制約のセットを提供します。resourceLimits オプションが Worker コンストラクターに渡された場合、これはその値と一致します。
ワーカーが停止した場合、戻り値は空のオブジェクトになります。
worker.stderr
Added in: v10.5.0
これは、ワーカー スレッド内の process.stderr に書き込まれたデータを含む読み取り可能なストリームです。stderr: true が Worker コンストラクターに渡されなかった場合、データは親スレッドの process.stderr ストリームにパイプされます。
worker.stdin
Added in: v10.5.0
stdin: true が Worker コンストラクターに渡された場合、これは書き込み可能なストリームです。このストリームに書き込まれたデータは、ワーカー スレッド内で process.stdin として利用可能になります。
worker.stdout
Added in: v10.5.0
これは、ワーカー スレッド内の process.stdout に書き込まれたデータを含む読み取り可能なストリームです。stdout: true が Worker コンストラクターに渡されなかった場合、データは親スレッドの process.stdout ストリームにパイプされます。
worker.terminate()
[履歴]
| バージョン | 変更点 |
|---|---|
| v12.5.0 | この関数は Promise を返すようになりました。コールバックを渡すことは非推奨であり、Worker は実際には同期的に終了していたため、このバージョンまでは役に立ちませんでした。終了は完全に非同期操作になりました。 |
| v10.5.0 | Added in: v10.5.0 |
- 戻り値: <Promise>
可能な限り早くワーカー スレッドでのすべての JavaScript 実行を停止します。'exit' イベント が発生したときに解決される終了コードの Promise を返します。
worker.threadId
Added in: v10.5.0
参照されるスレッドの整数識別子。ワーカー スレッド内では、require('node:worker_threads').threadId として利用できます。この値は、単一のプロセス内の各 Worker インスタンスに対して一意です。
worker.unref()
Added in: v10.5.0
ワーカーで unref() を呼び出すと、イベント システムでこれが唯一のアクティブなハンドルである場合に、スレッドが終了できます。ワーカーがすでに unref() されている場合、再度 unref() を呼び出しても効果はありません。
注記
stdio の同期的なブロッキング
Worker は、<MessagePort> を介したメッセージパッシングを利用して、stdio とのインタラクションを実装します。これは、Worker から発生した stdio 出力が、Node.js イベントループをブロックしている受信側の同期コードによってブロックされる可能性があることを意味します。
import {
Worker,
isMainThread,
} from 'node: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 オプションが明示的に設定されていない限り、新しい Worker スレッドは実行中のプロセスからコマンドラインフラグを自動的に継承し、メインスレッドと同じプリロードスクリプトをプリロードします。 プリロードスクリプトが無条件にワーカースレッドを起動する場合、生成されたすべてのスレッドはアプリケーションがクラッシュするまで別のスレッドを生成します。