Skip to content

ワーカートレッド

[安定版: 2 - 安定版]

安定版: 2 安定度: 2 - 安定版

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

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

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

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

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

js
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ドキュメントの"Using AsyncResource for a Worker thread pool"を参照してください。

ワーカースレッドは、デフォルトでプロセス固有ではないオプションを継承します。ワーカースレッドのオプション、特にargvexecArgvオプションをカスタマイズする方法については、Worker constructor optionsを参照してください。

worker.getEnvironmentData(key)

[履歴]

バージョン変更
v17.5.0, v16.15.0実験的ではなくなりました。
v15.12.0, v14.18.0追加: v15.12.0, v14.18.0
  • key <any> <Map> のキーとして使用できる、任意のクローン可能な JavaScript 値。
  • 戻り値: <any>

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

js
const { Worker, isMainThread, setEnvironmentData, getEnvironmentData } = require('node:worker_threads')

if (isMainThread) {
  setEnvironmentData('Hello', 'World!')
  const worker = new Worker(__filename)
} else {
  console.log(getEnvironmentData('Hello')) // 'World!' を出力します。
}

worker.isMainThread

追加: v10.5.0

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

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

if (isMainThread) {
  // これは、Worker インスタンス内で現在のファイルを読み込み直します。
  new Worker(__filename)
} else {
  console.log('Inside Worker!')
  console.log(isMainThread) // 'false' を出力します。
}

worker.markAsUntransferable(object)

追加: v14.5.0, v12.19.0

  • object <any> 任意の JavaScript 値。

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

特に、これは、転送するのではなくクローンできるオブジェクト、および送信側で他のオブジェクトによって使用されるオブジェクトにとって理にかなっています。たとえば、Node.js は、Buffer プール に使用する ArrayBuffer をこれを使ってマークします。

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

js
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 {
  // これはエラーをスローします。pooledBuffer は転送不可だからです。
  port1.postMessage(typedArray1, [typedArray1.buffer])
} catch (error) {
  // error.name === 'DataCloneError'
}

// 次の行は typedArray1 の内容を出力します -- これはまだメモリを所有しており、転送されていません。
// `markAsUntransferable()` がなければ、これは空の Uint8Array を出力し、postMessage コールは成功していました。
// typedArray2 も無傷です。
console.log(typedArray1)
console.log(typedArray2)

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

worker.isMarkedAsUntransferable(object)

追加:v21.0.0

markAsUntransferable()で転送不可としてマークされているかどうかをチェックします。

js
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 値。

オブジェクトを複製不可としてマークします。objectmessageとしてport.postMessage()呼び出しで使用された場合、エラーがスローされます。objectがプリミティブ値の場合、これはノーオペレーションです。

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

この操作は元に戻せません。

js
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

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

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

ただし、作成されたMessagePortEventTargetを継承しなくなり、port.onmessage()のみを使用してイベントを受信できます。

worker.parentPort

追加日時: v10.5.0

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

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

if (isMainThread) {
  const worker = new Worker(__filename)
  worker.once('message', message => {
    console.log(message) // 'Hello, world!'と出力します。
  })
  worker.postMessage('Hello, world!')
} else {
  // 親スレッドからのメッセージを受信したら、それを送り返します。
  parentPort.once('message', message => {
    parentPort.postMessage(message)
  })
}

worker.postMessageToThread(threadId, value[, transferList][, timeout])

追加日時: v22.5.0

[安定版: 1 - 実験的]

安定版: 1 安定性: 1。1 - アクティブ開発中

  • threadId <number> ターゲットスレッドの ID。スレッド ID が無効な場合、ERR_WORKER_MESSAGING_FAILEDエラーがスローされます。ターゲットスレッド ID が現在のスレッド ID の場合、ERR_WORKER_MESSAGING_SAME_THREADエラーがスローされます。
  • value <any> 送信する値。
  • transferList <Object[]> valueに 1 つ以上のMessagePortのようなオブジェクトが渡された場合、それらのアイテムには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 個のネストされたスレッドを作成し、最後の子スレッドがメインスレッドと通信しようとします。

js
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
js
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.0port引数は、BroadcastChannelも参照できるようになりました。
v12.3.0追加: v12.3.0

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

js
const { MessageChannel, receiveMessageOnPort } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
port1.postMessage({ hello: 'world' })

console.log(receiveMessageOnPort(port2))
// 出力: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2))
// 出力: undefined

この関数が使用されると、'message'イベントは発生せず、onmessageリスナーは呼び出されません。

worker.resourceLimits

追加: v13.2.0, v12.16.0

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

メインスレッドで使用した場合、その値は空のオブジェクトです。

worker.SHARE_ENV

追加日時: v11.14.0

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

js
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> クローンされて、新しいすべてのWorkerインスタンスに自動的に渡される任意のクローン可能な JavaScript 値。valueundefinedとして渡された場合、keyに対して以前に設定された値は削除されます。

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

worker.threadId

追加日時: v10.5.0

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

worker.workerData

追加版:v10.5.0

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

データは、HTML 構造化クローンアルゴリズムに従って、postMessage() を使用した場合と同じようにクローンされます。

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

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hello, world!' })
} else {
  console.log(workerData) // 'Hello, world!' と出力します。
}

クラス: BroadcastChannel extends EventTarget

[履歴]

バージョン変更点
v18.0.0実験的な段階ではなくなりました。
v15.4.0追加版:v15.4.0

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

js
'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

  • 型: <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インスタンスを参照するport1port2プロパティを持つオブジェクトを生成します。

js
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

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

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

イベント: 'close'

追加バージョン: v10.5.0

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

js
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> 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

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

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

  • value には循環参照を含めることができます。
  • value には、RegExpBigIntMapSet など、組み込みの JS 型のインスタンスを含めることができます。
  • value には、ArrayBufferSharedArrayBuffer の両方を使用する型付き配列を含めることができます。
  • value には WebAssembly.Module インスタンスを含めることができます。
  • value には、次のもの以外のネイティブ (C++ バックエンド) オブジェクトを含めることはできません。
js
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 は、ArrayBufferMessagePort、および FileHandle オブジェクトのリストにすることができます。転送後、それらはチャネルの送信側では使用できなくなります ( value に含まれていない場合でも)。子プロセス とは異なり、ネットワークソケットなどのハンドルの転送は現在サポートされていません。

valueSharedArrayBuffer インスタンスが含まれている場合、それらはどちらのスレッドからもアクセスできます。それらを transferList にリストすることはできません。

value には、transferList にない ArrayBuffer インスタンスが含まれている可能性があります。その場合、基礎となるメモリは移動されるのではなくコピーされます。

js
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 の転送時の考慮事項

全てのTypedArrayBufferインスタンスは、基となるArrayBufferへのビューです。つまり、生のデータを実際に格納するのはArrayBufferであり、TypedArrayBufferオブジェクトはデータの表示と操作の方法を提供します。同じArrayBufferインスタンスに対して複数のビューを作成することは可能であり、一般的です。転送リストを使用してArrayBufferを転送する際には細心の注意を払う必要があります。そうすることで、その同じArrayBufferを共有する全てのTypedArrayBufferインスタンスが使用できなくなってしまうためです。

js
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を所有していることが分かっている場合を除き、ArrayBufferを転送することはできません。特に、内部Bufferプールから作成されたBuffer(例えばBuffer.from()またはBuffer.allocUnsafe()を使用)の場合、それらを転送することは不可能であり、常にクローンされます。これにより、Bufferプールの全体のコピーが送信されます。この動作は、意図しないメモリ使用量の増加と、潜在的なセキュリティ上の問題を伴う可能性があります。

Bufferプーリングの詳細については、Buffer.allocUnsafe()を参照してください。

Buffer.alloc()またはBuffer.allocUnsafeSlow()を使用して作成されたBufferインスタンスのArrayBufferは常に転送できますが、そうすると、それらのArrayBufferの他の既存のビューは使用できなくなります。

プロトタイプ、クラス、アクセッサを持つオブジェクトを複製する場合の考慮事項

オブジェクトの複製はHTML 構造化複製アルゴリズムを使用するため、非列挙可能なプロパティ、プロパティアクセッサ、オブジェクトのプロトタイプは保持されません。特に、Bufferオブジェクトは受信側ではプレーンのUint8Arrayとして読み取られ、JavaScript クラスのインスタンスはプレーンの JavaScript オブジェクトとして複製されます。

js
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オブジェクトなどの多くの組み込みオブジェクトにも適用されます。

js
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

[安定版: 1 - 実験的]

安定版: 1 安定性: 1 - 実験的

trueの場合、MessagePortオブジェクトは Node.js イベントループをアクティブな状態に保ちます。

port.ref()

追加されたバージョン: v10.5.0

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

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

port.start()

追加日時: v10.5.0

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

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

port.unref()

追加日時: v10.5.0

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

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

クラス: Worker

追加日時: v10.5.0

Workerクラスは、独立した JavaScript 実行スレッドを表します。ほとんどの Node.js API は内部で使用できます。

Worker 環境内の注目すべき違いは次のとおりです。

  • 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モジュールと同様に、スレッド間のメッセージパッシングを通じて双方向通信を実現できます。内部的に、WorkerWorkerが作成された時点で既に互いに関連付けられている、組み込みのMessagePortのペアを持っています。親側のMessagePortオブジェクトは直接公開されていませんが、その機能はworker.postMessage()と親スレッドのWorkerオブジェクトのworker.on('message')イベントを介して公開されています。

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

メッセージの渡し方、およびスレッドの障壁を介して正常に転送できる JavaScript 値の種類の詳細については、port.postMessage()を参照してください。

js
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デバッグのためにワーカーのタイトルに名前を追加できるnameオプションのサポートを追加しました。
v14.9.0filenameパラメータは、data:プロトコルを使用する WHATWG URLオブジェクトを使用できます。
v14.9.0trackUnmanagedFdsオプションはデフォルトでtrueに設定されました。
v14.6.0, v12.19.0trackUnmanagedFdsオプションが導入されました。
v13.13.0, v12.17.0transferListオプションが導入されました。
v13.12.0, v12.17.0filenameパラメータは、file:プロトコルを使用する WHATWG URLオブジェクトを使用できます。
v13.4.0, v12.16.0argvオプションが導入されました。
v13.2.0, v12.16.0resourceLimitsオプションが導入されました。
v10.5.0追加: v10.5.0
  • filename <string> | <URL> ワーカーのメインスクリプトまたはモジュールのパス。絶対パスまたは./または../で始まる相対パス(つまり、現在の作業ディレクトリを基準とした相対パス)、またはfile:またはdata:プロトコルを使用する WHATWG URLオブジェクトのいずれかでなければなりません。data: URLを使用する場合、データは MIME タイプに基づいてECMAScript モジュールローダーを使用して解釈されます。options.evaltrueの場合、これはパスではなく JavaScript コードを含む文字列です。

  • options <Object>

    • argv <any[]> ワーカーのprocess.argvに追加される文字列に変換される引数のリスト。これは主にworkerDataに似ていますが、CLI オプションとしてスクリプトに渡されたかのように、グローバルなprocess.argvで値を利用できます。

    • env <Object> 設定されている場合、ワーカスレッド内のprocess.envの初期値を指定します。特殊な値として、worker.SHARE_ENVを使用して、親スレッドと子スレッドが環境変数を共有する必要があることを指定できます。その場合、一方のスレッドのprocess.envオブジェクトへの変更は、もう一方のスレッドにも影響します。デフォルト: process.env

    • eval <boolean> trueの場合、最初の引数がstringであり、コンストラクタへの最初の引数を、ワーカーがオンラインになったときに実行されるスクリプトとして解釈します。

    • execArgv <string[]> ワーカーに渡されるノード CLI オプションのリスト。V8 オプション(--max-old-space-sizeなど)とプロセスに影響を与えるオプション(--titleなど)はサポートされていません。設定されている場合、これはワーカー内でprocess.execArgvとして提供されます。デフォルトでは、オプションは親スレッドから継承されます。

    • stdin <boolean> これがtrueに設定されている場合、worker.stdinは、その内容がワーカー内の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[]> workerDataに 1 つ以上のMessagePortのようなオブジェクトが渡された場合、これらのアイテムにはtransferListが必要です。そうでない場合、ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LISTがスローされます。詳細については、port.postMessage()を参照してください。

    • resourceLimits <Object> 新しい JS エンジンインスタンスのリソース制限のオプションセット。これらの制限に達すると、Workerインスタンスが終了します。これらの制限は JS エンジンにのみ影響し、外部データ(ArrayBufferを含まない)には影響しません。これらの制限が設定されている場合でも、グローバルなメモリ不足が発生した場合、プロセスは依然として異常終了する可能性があります。

    • maxOldGenerationSizeMb <number> メインヒープの最大サイズ(MB 単位)。コマンドライン引数--max-old-space-sizeが設定されている場合、この設定よりも優先されます。

    • maxYoungGenerationSizeMb <number> 最近作成されたオブジェクトのヒープスペースの最大サイズ。コマンドライン引数--max-semi-space-sizeが設定されている場合、この設定よりも優先されます。

    • codeRangeSizeMb <number> 生成されたコードに使用される事前に割り当てられたメモリ範囲のサイズ。

    • stackSizeMb <number> スレッドのデフォルトの最大スタックサイズ。小さい値では、使用できないワーカーインスタンスが発生する可能性があります。デフォルト: 4

    • name <string> デバッグ/識別目的でワーカーのタイトルに追加されるオプションのname。最終的なタイトルは[worker ${id}] ${name}となります。デフォルト: ''

イベント: 'error'

追加日時: v10.5.0

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

イベント: 'exit'

追加日時: v10.5.0

'exit' イベントは、ワーカーが停止した後に発生します。ワーカーがprocess.exit()を呼び出して終了した場合、exitCode パラメーターは渡された終了コードになります。ワーカーが強制終了された場合、exitCode パラメーターは1になります。

これは、任意のWorkerインスタンスによって発生する最後のイベントです。

イベント: 'message'

追加日時: v10.5.0

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

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

イベント: '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
  • options <オブジェクト>

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

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

'exit' イベントが発生する前にワーカスレッドが実行されなくなると、返されるPromiseERR_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時間が蓄積されないにもかかわらず、メッセージを処理できることを示しています。

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

追加日時: v10.5.0

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

worker.ref()

追加日時: v10.5.0

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

worker.resourceLimits

追加日時: v13.2.0, v12.16.0

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

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

worker.stderr

追加日時: v10.5.0

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

worker.stdin

追加されたバージョン: v10.5.0

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

worker.stdout

追加されたバージョン: v10.5.0

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

worker.terminate()

[履歴]

バージョン変更点
v12.5.0この関数は Promise を返すようになりました。コールバックの渡しが非推奨となり、このバージョンまでは実際にはワーカーは同期的に終了していたため、役に立ちませんでした。終了は完全に非同期操作になりました。
v10.5.0追加されました: v10.5.0

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

worker.threadId

追加されたバージョン: v10.5.0

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

worker.unref()

追加されたバージョン: v10.5.0

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

メモ

stdio の同期ブロッキング

Workerは、<MessagePort>を介したメッセージパッシングを使用してstdioとのやり取りを実装します。これは、Workerから発信されるstdio出力は、Node.js イベントループをブロックしている受信側の同期コードによってブロックされる可能性があることを意味します。

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')
}
js
'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オプションを明示的に設定しない限り、新しいワーカスレッドは実行中のプロセスからコマンドラインフラグを自動的に継承し、メインスレッドと同じプリロードスクリプトをプリロードします。プリロードスクリプトがワーカスレッドを無条件に起動する場合、生成されたすべてのスレッドがさらに別のスレッドを生成し、アプリケーションがクラッシュするまで続きます。