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()
を介して管理される生のファイル記述子を追跡し、FileHandle
API を介して管理されるネットワークソケットやファイル記述子などの他のリソースと同様に、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 スレッドは実行中のプロセスからコマンドラインフラグを自動的に継承し、メインスレッドと同じプリロードスクリプトをプリロードします。 プリロードスクリプトが無条件にワーカースレッドを起動する場合、生成されたすべてのスレッドはアプリケーションがクラッシュするまで別のスレッドを生成します。