ワーカースレッド#

安定性: 2 - Stable

ソースコード: lib/worker_threads.js

node:worker_threadsモジュールは、JavaScriptを並列に実行するスレッドの使用を可能にします。アクセスするには

import worker_threads from 'node:worker_threads';'use strict';

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

ワーカー(スレッド)は、CPU集約的なJavaScript操作を実行するのに役立ちます。I/O集約的な作業にはあまり役立ちません。Node.jsに組み込まれている非同期I/O操作は、ワーカーよりも効率的です。

child_processclusterとは異なり、worker_threadsはメモリを共有できます。これは、ArrayBufferインスタンスを転送したり、SharedArrayBufferインスタンスを共有したりすることによって行われます。

import {
  Worker,
  isMainThread,
  parentPort,
  workerData,
} from 'node:worker_threads';

if (!isMainThread) {
  const { parse } = await import('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}

export default function parseJSAsync(script) {
  return new Promise((resolve, reject) => {
    const worker = new Worker(new URL(import.meta.url), {
      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}`));
    });
  });
};'use strict';

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_threads.getEnvironmentData(key)#

  • key <any> <Map>のキーとして使用できる、任意のクローン可能なJavaScript値。
  • 戻り値: <any>

ワーカースレッド内で、worker.getEnvironmentData()は、生成元のスレッドのworker.setEnvironmentData()に渡されたデータのクローンを返します。すべての新しいWorkerは、自動的に環境データの独自のコピーを受け取ります。

import {
  Worker,
  isMainThread,
  setEnvironmentData,
  getEnvironmentData,
} from 'node:worker_threads';

if (isMainThread) {
  setEnvironmentData('Hello', 'World!');
  const worker = new Worker(new URL(import.meta.url));
} else {
  console.log(getEnvironmentData('Hello'));  // Prints 'World!'.
}'use strict';

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_threads.isInternalThread#

このコードが内部のWorkerスレッド(例: ローダースレッド)内で実行されている場合はtrueです。

node --experimental-loader ./loader.js main.js 
// loader.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread);  // true// loader.js
'use strict';

const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread);  // true
// main.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread);  // false// main.js
'use strict';

const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread);  // false

worker_threads.isMainThread#

このコードがWorkerスレッド内で実行されていない場合はtrueです。

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

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

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_threads.markAsUntransferable(object)#

  • object <any> 任意のJavaScript値。

オブジェクトを転送不可能としてマークします。objectport.postMessage()呼び出しの転送リストに含まれている場合、エラーがスローされます。objectがプリミティブ値の場合、これは何もしません。

特に、これは転送されるのではなくクローンされる可能性があり、送信側で他のオブジェクトによって使用されるオブジェクトに意味があります。例えば、Node.jsはBufferプールに使用するArrayBufferをこれでマークします。

この操作は元に戻すことはできません。

import { MessageChannel, markAsUntransferable } from '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);'use strict';

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_threads.isMarkedAsUntransferable(object)#

オブジェクトがmarkAsUntransferable()で転送不可能としてマークされているかどうかを確認します。

import { markAsUntransferable, isMarkedAsUntransferable } from 'node:worker_threads';

const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);

isMarkedAsUntransferable(pooledBuffer);  // Returns true.'use strict';

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

const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);

isMarkedAsUntransferable(pooledBuffer);  // Returns true.

ブラウザにはこのAPIに相当するものはありません。

worker_threads.markAsUncloneable(object)#

  • object <any> 任意のJavaScript値。

オブジェクトをクローン不可能としてマークします。objectport.postMessage()呼び出しのmessageとして使用された場合、エラーがスローされます。objectがプリミティブ値の場合、これは何もしません。

これはArrayBufferや、Bufferのようなオブジェクトには影響しません。

この操作は元に戻すことはできません。

import { markAsUncloneable } from 'node:worker_threads';

const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
  // This will throw an error, because anyObject is not cloneable.
  port1.postMessage(anyObject);
} catch (error) {
  // error.name === 'DataCloneError'
}'use strict';

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

const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
  // This will throw an error, because anyObject is not cloneable.
  port1.postMessage(anyObject);
} catch (error) {
  // error.name === 'DataCloneError'
}

ブラウザにはこのAPIに相当するものはありません。

worker_threads.moveMessagePortToContext(port, contextifiedSandbox)#

MessagePortを異なるvmコンテキストに転送します。元のportオブジェクトは使用不可になり、返されたMessagePortインスタンスがその代わりとなります。

返されたMessagePortはターゲットコンテキスト内のオブジェクトであり、そのグローバルObjectクラスから継承します。port.onmessage()リスナーに渡されるオブジェクトもターゲットコンテキストで作成され、そのグローバルObjectクラスから継承します。

ただし、作成されたMessagePortはもはや<EventTarget>から継承せず、イベントを受信するために使用できるのはport.onmessage()のみです。

worker_threads.parentPort#

このスレッドがWorkerである場合、これは親スレッドとの通信を可能にするMessagePortです。parentPort.postMessage()を使用して送信されたメッセージは、親スレッドでworker.on('message')を使用して利用可能になり、親スレッドからworker.postMessage()を使用して送信されたメッセージは、このスレッドでparentPort.on('message')を使用して利用可能になります。

import { Worker, isMainThread, parentPort } from 'node:worker_threads';

if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url));
  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);
  });
}'use strict';

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_threads.postMessageToThread(threadId, value[, transferList][, timeout])#

安定性: 1.1 - Active development

  • 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> メッセージが宛先スレッドによって正常に処理された場合に解決されるプロミス。

スレッドIDで識別される別のワーカーに値を送信します。

ターゲットスレッドにworkerMessageイベントのリスナーがない場合、操作はERR_WORKER_MESSAGING_FAILEDエラーをスローします。

ターゲットスレッドがworkerMessageイベントの処理中にエラーをスローした場合、操作はERR_WORKER_MESSAGING_ERROREDエラーをスローします。

このメソッドは、ターゲットスレッドが現在のスレッドの直接の親または子でない場合に使用する必要があります。2つのスレッドが親子関係にある場合は、require('node:worker_threads').parentPort.postMessage()worker.postMessage()を使用してスレッド間で通信させます。

以下の例はpostMessageToThreadの使用法を示しています。10個のネストされたスレッドを作成し、最後のスレッドがメインスレッドと通信しようとします。

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(new URL(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;'use strict';

const process = require('node:process');
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_threads.receiveMessageOnPort(port)#

指定されたMessagePortから単一のメッセージを受信します。メッセージが利用できない場合はundefinedが返され、それ以外の場合はMessagePortのキュー内の最も古いメッセージに対応するメッセージペイロードを含む単一のmessageプロパティを持つオブジェクトが返されます。

import { MessageChannel, receiveMessageOnPort } from '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'use strict';

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_threads.resourceLimits#

このワーカースレッド内のJSエンジンのリソース制約のセットを提供します。resourceLimitsオプションがWorkerコンストラクタに渡された場合、これはその値と一致します。

これがメインスレッドで使用される場合、その値は空のオブジェクトです。

worker_threads.SHARE_ENV#

Workerコンストラクタのenvオプションとして渡すことができる特別な値で、現在のスレッドとワーカースレッドが同じ環境変数セットへの読み取りおよび書き込みアクセスを共有することを示します。

import process from 'node:process';
import { Worker, SHARE_ENV } from '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'.
  });'use strict';

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_threads.setEnvironmentData(key[, value])#

  • key <any> <Map>のキーとして使用できる、任意のクローン可能なJavaScript値。
  • value <any> 任意のクローン可能なJavaScript値で、クローンされてすべての新しいWorkerインスタンスに自動的に渡されます。valueundefinedとして渡された場合、以前に設定されたkeyの値は削除されます。

worker.setEnvironmentData()APIは、現在のスレッドと、現在のコンテキストから生成されたすべての新しいWorkerインスタンスのworker.getEnvironmentData()の内容を設定します。

worker_threads.threadId#

現在のスレッドの整数識別子。対応するワーカーオブジェクト(もしあれば)では、worker.threadIdとして利用できます。この値は、単一プロセス内の各Workerインスタンスに対して一意です。

worker_threads.threadName#

現在のスレッドの文字列識別子、またはスレッドが実行されていない場合はnull。対応するワーカーオブジェクト(もしあれば)では、worker.threadNameとして利用できます。

worker_threads.workerData#

このスレッドのWorkerコンストラクタに渡されたデータのクローンを含む任意のJavaScript値。

データは、HTML構造化クローンアルゴリズムに従って、postMessage()を使用するかのようにクローンされます。

import { Worker, isMainThread, workerData } from 'node:worker_threads';

if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url), { workerData: 'Hello, world!' });
} else {
  console.log(workerData);  // Prints 'Hello, world!'.
}'use strict';

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!'.
}

worker_threads.locks#

安定性: 1 - Experimental

同一プロセス内の複数のスレッド間で共有される可能性のあるリソースへのアクセスを調整するために使用できるLockManagerのインスタンス。このAPIは、ブラウザのLockManagerのセマンティクスを反映しています。

クラス: Lock#

Lockインターフェースは、locks.request()を介して許可されたロックに関する情報を提供します。

lock.name#

ロックの名前。

lock.mode#

ロックのモード。sharedまたはexclusiveのいずれかです。

クラス: LockManager#

LockManagerインターフェースは、ロックの要求と調査のためのメソッドを提供します。LockManagerインスタンスを取得するには、以下を使用します。

import { locks } from 'node:worker_threads';'use strict';

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

この実装はブラウザのLockManagerAPIと一致します。

locks.request(name[, options], callback)#
  • name <string>
  • options <Object>
    • mode <string> 'exclusive'または'shared'のいずれか。デフォルト: 'exclusive'
    • ifAvailable <boolean> trueの場合、リクエストはロックがまだ保持されていない場合にのみ許可されます。許可できない場合、callbackLockインスタンスの代わりにnullで呼び出されます。デフォルト: false
    • steal <boolean> trueの場合、同じ名前の既存のロックはすべて解放され、リクエストはキューに入っているリクエストを先取りして即座に許可されます。デフォルト: false
    • signal <AbortSignal> 保留中(まだ許可されていない)のロックリクエストを中止するために使用できます。
  • callback <Function> ロックが許可されると(またはifAvailabletrueでロックが利用できない場合は即座にnullで)呼び出されます。ロックは関数が返ると自動的に解放されるか、関数がプロミスを返す場合は、そのプロミスが解決したときに解放されます。
  • 戻り値: <Promise> ロックが解放された後に解決されます。
import { locks } from 'node:worker_threads';

await locks.request('my_resource', async (lock) => {
  // The lock has been acquired.
});
// The lock has been released here.'use strict';

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

locks.request('my_resource', async (lock) => {
  // The lock has been acquired.
}).then(() => {
  // The lock has been released here.
});
locks.query()#

現在のプロセスで現在保持されているロックと保留中のロックを記述するLockManagerSnapshotで解決します。

import { locks } from 'node:worker_threads';

const snapshot = await locks.query();
for (const lock of snapshot.held) {
  console.log(`held lock: name ${lock.name}, mode ${lock.mode}`);
}
for (const pending of snapshot.pending) {
  console.log(`pending lock: name ${pending.name}, mode ${pending.mode}`);
}'use strict';

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

locks.query().then((snapshot) => {
  for (const lock of snapshot.held) {
    console.log(`held lock: name ${lock.name}, mode ${lock.mode}`);
  }
  for (const pending of snapshot.pending) {
    console.log(`pending lock: name ${pending.name}, mode ${pending.mode}`);
  }
});

クラス: BroadcastChannel extends EventTarget#

BroadcastChannelのインスタンスは、同じチャネル名にバインドされた他のすべてのBroadcastChannelインスタンスとの非同期の1対多通信を可能にします。

import {
  isMainThread,
  BroadcastChannel,
  Worker,
} from '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(new URL(import.meta.url));
} else {
  bc.postMessage('hello from every worker');
  bc.close();
}'use strict';

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

const bc = new BroadcastChannel('hello');

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

new BroadcastChannel(name)#

  • name <any> 接続するチャネルの名前。`${name}`を使用して文字列に変換できる任意のJavaScript値が許可されます。

broadcastChannel.close()#

BroadcastChannel接続を閉じます。

broadcastChannel.onmessage#

  • 型: <Function> メッセージが受信されたときに単一のMessageEvent引数で呼び出されます。

broadcastChannel.onmessageerror#

  • 型: <Function> 受信したメッセージがデシリアライズできない場合に呼び出されます。

broadcastChannel.postMessage(message)#

  • message <any> 任意のクローン可能なJavaScript値。

broadcastChannel.ref()#

unref()の反対です。以前にunref()されたBroadcastChannelでref()を呼び出しても、それが唯一のアクティブなハンドルである場合でもプログラムは終了しません(デフォルトの動作)。ポートがref()されている場合、再度ref()を呼び出しても効果はありません。

broadcastChannel.unref()#

BroadcastChannelでunref()を呼び出すと、これがイベントシステムで唯一のアクティブなハンドルである場合にスレッドを終了させることができます。BroadcastChannelがすでにunref()されている場合、再度unref()を呼び出しても効果はありません。

クラス: MessageChannel#

worker.MessageChannelクラスのインスタンスは、非同期の双方向通信チャネルを表します。MessageChannelには独自のメソッドはありません。new MessageChannel()は、リンクされたMessagePortインスタンスを参照するport1port2プロパティを持つオブジェクトを生成します。

import { MessageChannel } from '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'use strict';

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クラスのインスタンスは、非同期の双方向通信チャネルの一端を表します。構造化データ、メモリ領域、その他のMessagePortを異なるWorker間で転送するために使用できます。

この実装はブラウザのMessagePortと一致します。

イベント: 'close'#

'close'イベントは、チャネルのどちらかの側が切断されると一度だけ発生します。

import { MessageChannel } from '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();'use strict';

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> Errorオブジェクト

'messageerror'イベントは、メッセージのデシリアライズに失敗したときに発生します。

現在、このイベントは、受信側でポストされたJSオブジェクトをインスタンス化する際にエラーが発生した場合に発生します。このような状況はまれですが、たとえば、特定のNode.js APIオブジェクトがvm.Context(現在Node.js APIが利用できない場所)で受信された場合に発生する可能性があります。

port.close()#

接続の両側でのメッセージのさらなる送信を無効にします。このメソッドは、このMessagePortを介してそれ以上の通信が行われない場合に呼び出すことができます。

'close'イベントは、チャネルの一部である両方のMessagePortインスタンスで発生します。

port.postMessage(value[, transferList])#

このチャネルの受信側にJavaScript値を送信します。valueHTML構造化クローンアルゴリズムと互換性のある方法で転送されます。

特に、JSONとの重要な違いは次のとおりです

  • valueには循環参照が含まれている場合があります。
  • valueには、RegExpBigIntMapSetなどの組み込みJS型のインスタンスが含まれている場合があります。
  • valueには、ArrayBufferSharedArrayBufferの両方を使用した型付き配列が含まれている場合があります。
  • valueにはWebAssembly.Moduleインスタンスが含まれている場合があります。
  • valueには、以下以外のネイティブ(C++バック)オブジェクトを含めることはできません。
import { MessageChannel } from '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);'use strict';

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インスタンスが含まれている場合があります。その場合、基になるメモリは移動されるのではなくコピーされます。

import { MessageChannel } from '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 ]);'use strict';

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を転送できるかクローンできるかは、インスタンスがどのように作成されたかに完全に依存し、これはしばしば確実に判断できません。

ArrayBuffermarkAsUntransferable()でマークして、常にクローンされ、決して転送されないように指示できます。

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()されたポートでref()を呼び出しても、それが唯一のアクティブなハンドルである場合でもプログラムは終了しません(デフォルトの動作)。ポートがref()されている場合、再度ref()を呼び出しても効果はありません。

.on('message')を使用してリスナーがアタッチまたは削除された場合、ポートはイベントのリスナーが存在するかどうかに応じて自動的にref()およびunref()されます。

port.start()#

このMessagePortでメッセージの受信を開始します。このポートをイベントエミッタとして使用する場合、'message'リスナーがアタッチされると自動的に呼び出されます。

このメソッドは、WebのMessagePortAPIとの互換性のために存在します。Node.jsでは、イベントリスナーが存在しない場合にメッセージを無視するためにのみ役立ちます。Node.jsは、.onmessageの処理においても異なります。これを設定すると自動的に.start()が呼び出されますが、設定を解除すると、新しいハンドラが設定されるかポートが破棄されるまでメッセージがキューに入れられます。

port.unref()#

ポートでunref()を呼び出すと、これがイベントシステムで唯一のアクティブなハンドルである場合にスレッドを終了させることができます。ポートがすでにunref()されている場合、再度unref()を呼び出しても効果はありません。

.on('message')を使用してリスナーがアタッチまたは削除された場合、ポートはイベントのリスナーが存在するかどうかに応じて自動的にref()およびunref()されます。

クラス: Worker#

Workerクラスは、独立したJavaScript実行スレッドを表します。ほとんどのNode.js APIがその中で利用可能です。

ワーカー環境内の注目すべき違いは

  • process.stdinprocess.stdout、およびprocess.stderrストリームは、親スレッドによってリダイレクトされる場合があります。
  • require('node:worker_threads').isMainThreadプロパティはfalseに設定されます。
  • require('node:worker_threads').parentPortメッセージポートが利用可能です。
  • process.exit()はプログラム全体を停止せず、単一のスレッドのみを停止し、process.abort()は利用できません。
  • process.chdir()およびグループIDまたはユーザーIDを設定するprocessメソッドは利用できません。
  • process.envは、特に指定がない限り、親スレッドの環境変数のコピーです。一方のコピーへの変更は他のスレッドからは見えず、ネイティブアドオンからも見えません(worker.SHARE_ENVWorkerコンストラクタのenvオプションとして渡されない限り)。Windowsでは、メインスレッドとは異なり、環境変数のコピーはケースセンシティブに動作します。
  • process.titleは変更できません。
  • シグナルはprocess.on('...')を介して配信されません。
  • worker.terminate()が呼び出された結果として、実行はいつでも停止する可能性があります。
  • 親プロセスからのIPCチャネルにはアクセスできません。
  • trace_eventsモジュールはサポートされていません。
  • ネイティブアドオンは、特定の条件を満たしている場合にのみ複数のスレッドからロードできます。

他のWorker内でWorkerインスタンスを作成することが可能です。

Web Workersnode:clusterモジュールと同様に、スレッド間のメッセージパッシングを通じて双方向通信を実現できます。内部的に、Workerには、Workerが作成されたときにすでに関連付けられている組み込みのMessagePortのペアがあります。親側のMessagePortオブジェクトは直接公開されていませんが、その機能は親スレッドのWorkerオブジェクトのworker.postMessage()およびworker.on('message')イベントを通じて公開されています。

カスタムメッセージングチャネルを作成するには(関心の分離を促進するため、デフォルトのグローバルチャネルを使用するよりも推奨されます)、ユーザーはどちらかのスレッドでMessageChannelオブジェクトを作成し、そのMessageChannelMessagePortの1つを、グローバルチャネルなどの既存のチャネルを通じて他のスレッドに渡すことができます。

メッセージがどのように渡され、どのような種類のJavaScript値がスレッドの境界を越えて正常に輸送できるかについての詳細は、port.postMessage()を参照してください。

import assert from 'node:assert';
import {
  Worker, MessageChannel, MessagePort, isMainThread, parentPort,
} from 'node:worker_threads';
if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url));
  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();
  });
}'use strict';

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

new Worker(filename[, options])#

  • filename <string> | <URL> ワーカーのメインスクリプトまたはモジュールへのパス。絶対パス、または./または../で始まる相対パス(つまり、現在の作業ディレクトリからの相対パス)、あるいはfile:またはdata:プロトコルを使用するWHATWG URLオブジェクトのいずれかである必要があります。data: URLを使用する場合、データはECMAScriptモジュールローダーを使用してMIMEタイプに基づいて解釈されます。options.evaltrueの場合、これはパスではなくJavaScriptコードを含む文字列です。
  • options <Object>
    • argv <any[]> ワーカーのprocess.argvに文字列化されて追加される引数のリスト。これはほとんどworkerDataに似ていますが、値はグローバルなprocess.argv上で、スクリプトにCLIオプションとして渡されたかのように利用できます。
    • env <Object> 設定されている場合、ワーカースレッド内のprocess.envの初期値を指定します。特別な値として、worker.SHARE_ENVを使用して、親スレッドと子スレッドが環境変数を共有するように指定できます。その場合、一方のスレッドのprocess.envオブジェクトへの変更は、他のスレッドにも影響します。デフォルト: process.env
    • eval <boolean> trueで、最初の引数がstringの場合、コンストラクタの最初の引数を、ワーカーがオンラインになったときに一度だけ実行されるスクリプトとして解釈します。
    • execArgv <string[]> ワーカーに渡されるnode CLIオプションのリスト。V8オプション(--max-old-space-sizeなど)やプロセスに影響を与えるオプション(--titleなど)はサポートされていません。設定されている場合、これはワーカー内でprocess.execArgvとして提供されます。デフォルトでは、オプションは親スレッドから継承されます。
    • stdin <boolean> これがtrueに設定されている場合、worker.stdinは、その内容がワーカー内でprocess.stdinとして表示される書き込み可能なストリームを提供します。デフォルトでは、データは提供されません。
    • stdout <boolean> これがtrueに設定されている場合、worker.stdoutは親のprocess.stdoutに自動的にパイプされません。
    • stderr <boolean> これがtrueに設定されている場合、worker.stderrは親のprocess.stderrに自動的にパイプされません。
    • workerData <any> クローンされてrequire('node:worker_threads').workerDataとして利用可能になる任意のJavaScript値。クローンはHTML構造化クローンアルゴリズムで説明されているように行われ、オブジェクトがクローンできない場合(例えば、functionを含むため)はエラーがスローされます。
    • trackUnmanagedFds <boolean> これがtrueに設定されている場合、ワーカーはfs.open()およびfs.close()を通じて管理される生のファイルディスクリプタを追跡し、ワーカーが終了するときにそれらを閉じます。これは、ネットワークソケットやFileHandleAPIを通じて管理されるファイルディスクリプタなどの他のリソースと同様です。このオプションは、すべてのネストされた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> デバッグ/識別の目的で、スレッド名とワーカータイトルで置き換えられるオプションのnameで、最終的なタイトルは[worker ${id}] ${name}となります。このパラメータには、オペレーティングシステムに応じて最大許容サイズがあります。指定された名前が制限を超えた場合、切り捨てられます。
      • 最大サイズ
        • Windows: 32,767文字
        • macOS: 64文字
        • Linux: 16文字
        • NetBSD: PTHREAD_MAX_NAMELEN_NPに制限
        • FreeBSDとOpenBSD: MAXCOMLENに制限 デフォルト: 'WorkerThread'

イベント: 'error'#

'error'イベントは、ワーカースレッドがキャッチされない例外をスローした場合に発生します。その場合、ワーカーは終了します。

イベント: 'exit'#

'exit'イベントは、ワーカーが停止したときに一度だけ発生します。ワーカーがprocess.exit()を呼び出して終了した場合、exitCodeパラメータは渡された終了コードです。ワーカーが終了させられた場合、exitCodeパラメータは1です。

これは、どのWorkerインスタンスによっても発行される最後のイベントです。

イベント: 'message'#

  • value <any> 送信された値

'message'イベントは、ワーカースレッドがrequire('node:worker_threads').parentPort.postMessage()を呼び出したときに発生します。詳細については、port.on('message')イベントを参照してください。

ワーカースレッドから送信されたすべてのメッセージは、Workerオブジェクトで'exit'イベントが発生する前に発行されます。

イベント: 'messageerror'#

  • error <Error> Errorオブジェクト

'messageerror'イベントは、メッセージのデシリアライズに失敗したときに発生します。

イベント: 'online'#

'online'イベントは、ワーカースレッドがJavaScriptコードの実行を開始したときに発生します。

worker.cpuUsage([prev])#

このメソッドは、process.threadCpuUsage()と同一のオブジェクトに解決されるPromiseを返すか、ワーカーがもはや実行されていない場合はERR_WORKER_NOT_RUNNINGエラーで拒否します。このメソッドにより、実際のスレッドの外部から統計を監視できます。

worker.getHeapSnapshot([options])#

  • options <Object>
    • exposeInternals <boolean> trueの場合、ヒープスナップショットに内部を公開します。デフォルト: false
    • exposeNumericValues <boolean> trueの場合、人工的なフィールドに数値を公開します。デフォルト: false
  • 戻り値: <Promise> V8ヒープスナップショットを含むReadable Streamのプロミス

ワーカーの現在の状態のV8スナップショットの読み取り可能なストリームを返します。詳細については、v8.getHeapSnapshot()を参照してください。

ワーカースレッドがもはや実行されていない場合('exit'イベントが発生する前に発生する可能性があります)、返されたPromiseはすぐにERR_WORKER_NOT_RUNNINGエラーで拒否されます。

worker.getHeapStatistics()#

このメソッドは、v8.getHeapStatistics()と同一のオブジェクトに解決されるPromiseを返すか、ワーカーがもはや実行されていない場合はERR_WORKER_NOT_RUNNINGエラーで拒否します。このメソッドにより、実際のスレッドの外部から統計を監視できます。

worker.performance#

ワーカーインスタンスからパフォーマンス情報をクエリするために使用できるオブジェクト。perf_hooks.performanceに似ています。

performance.eventLoopUtilization([utilization1[, utilization2]])#
  • utilization1 <Object> 以前のeventLoopUtilization()呼び出しの結果。
  • utilization2 <Object> utilization1より前のeventLoopUtilization()呼び出しの結果。
  • 戻り値: <Object>

perf_hookseventLoopUtilization()と同じ呼び出しですが、ワーカーインスタンスの値が返されます。

1つの違いは、メインスレッドとは異なり、ワーカー内のブートストラップはイベントループ内で行われることです。そのため、イベントループの使用率は、ワーカーのスクリプトが実行を開始するとすぐに利用可能になります。

増加しないidle時間は、ワーカーがブートストラップでスタックしていることを示しません。以下の例は、ワーカーの全ライフサイクルでidle時間がまったく蓄積されないにもかかわらず、メッセージを処理できることを示しています。

import { Worker, isMainThread, parentPort } from 'node:worker_threads';

if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url));
  setInterval(() => {
    worker.postMessage('hi');
    console.log(worker.performance.eventLoopUtilization());
  }, 100).unref();
} else {
  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);
}'use strict';

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

ワーカーのイベントループ使用率は、'online'イベントが発生した後にのみ利用可能であり、これより前、または'exit'イベントの後に呼び出された場合、すべてのプロパティの値は0になります。

worker.postMessage(value[, transferList])#

require('node:worker_threads').parentPort.on('message')を介して受信されるメッセージをワーカーに送信します。詳細については、port.postMessage()を参照してください。

worker.ref()#

unref()の反対で、以前にunref()されたワーカーでref()を呼び出しても、それが唯一のアクティブなハンドルである場合でもプログラムは終了しません(デフォルトの動作)。ワーカーがref()されている場合、再度ref()を呼び出しても効果はありません。

worker.resourceLimits#

このワーカースレッドのJSエンジンリソース制約のセットを提供します。resourceLimitsオプションがWorkerコンストラクタに渡された場合、これはその値と一致します。

ワーカーが停止した場合、戻り値は空のオブジェクトです。

worker.startCpuProfile()#

CPUプロファイルを開始し、エラーまたはCPUProfileHandleオブジェクトで解決されるPromiseを返します。このAPIはawait using構文をサポートしています。

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

const worker = new Worker(`
  const { parentPort } = require('worker_threads');
  parentPort.on('message', () => {});
  `, { eval: true });

worker.on('online', async () => {
  const handle = await worker.startCpuProfile();
  const profile = await handle.stop();
  console.log(profile);
  worker.terminate();
}); 

await usingの例。

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

const w = new Worker(`
  const { parentPort } = require('node:worker_threads');
  parentPort.on('message', () => {});
  `, { eval: true });

w.on('online', async () => {
  // Stop profile automatically when return and profile will be discarded
  await using handle = await w.startCpuProfile();
}); 

worker.startHeapProfile()#

ヒーププロファイルを開始し、エラーまたはHeapProfileHandleオブジェクトで解決されるPromiseを返します。このAPIはawait using構文をサポートしています。

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

const worker = new Worker(`
  const { parentPort } = require('worker_threads');
  parentPort.on('message', () => {});
  `, { eval: true });

worker.on('online', async () => {
  const handle = await worker.startHeapProfile();
  const profile = await handle.stop();
  console.log(profile);
  worker.terminate();
}); 

await usingの例。

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

const w = new Worker(`
  const { parentPort } = require('node:worker_threads');
  parentPort.on('message', () => {});
  `, { eval: true });

w.on('online', async () => {
  // Stop profile automatically when return and profile will be discarded
  await using handle = await w.startHeapProfile();
}); 

worker.stderr#

これは、ワーカースレッド内のprocess.stderrに書き込まれたデータを含む読み取り可能なストリームです。stderr: trueWorkerコンストラクタに渡されなかった場合、データは親スレッドのprocess.stderrストリームにパイプされます。

worker.stdin#

stdin: trueWorkerコンストラクタに渡された場合、これは書き込み可能なストリームです。このストリームに書き込まれたデータは、ワーカースレッド内でprocess.stdinとして利用可能になります。

worker.stdout#

これは、ワーカースレッド内のprocess.stdoutに書き込まれたデータを含む読み取り可能なストリームです。stdout: trueWorkerコンストラクタに渡されなかった場合、データは親スレッドのprocess.stdoutストリームにパイプされます。

worker.terminate()#

ワーカースレッド内のすべてのJavaScript実行をできるだけ早く停止します。'exit'イベントが発生したときに解決される終了コードのPromiseを返します。

worker.threadId#

参照されるスレッドの整数識別子。ワーカースレッド内では、require('node:worker_threads').threadIdとして利用できます。この値は、単一プロセス内の各Workerインスタンスに対して一意です。

worker.threadName#

参照されるスレッドの文字列識別子、またはスレッドが実行されていない場合はnull。ワーカースレッド内では、require('node:worker_threads').threadNameとして利用できます。

worker.unref()#

ワーカーでunref()を呼び出すと、これがイベントシステムで唯一のアクティブなハンドルである場合にスレッドを終了させることができます。ワーカーがすでにunref()されている場合、再度unref()を呼び出しても効果はありません。

worker[Symbol.asyncDispose]()#

破棄スコープが終了したときにworker.terminate()を呼び出します。

async function example() {
  await using worker = new Worker('for (;;) {}', { eval: true });
  // Worker is automatically terminate when the scope is exited.
} 

注意#

stdioの同期ブロッキング#

Workerは、stdioとの相互作用を実装するために<MessagePort>を介したメッセージパッシングを利用します。これは、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++) {
    // 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オプションが明示的に設定されていない限り、新しいワーカースレッドは実行中のプロセスからコマンドラインフラグを自動的に継承し、メインスレッドと同じプリロードスクリプトをプリロードします。プリロードスクリプトが無条件にワーカースレッドを起動する場合、生成されたすべてのスレッドがアプリケーションがクラッシュするまで別のスレッドを生成します。