Threads de trabalhador
[Estável: 2 - Estável]
Estável: 2 Estabilidade: 2 - Estável
Código-fonte: lib/worker_threads.js
O módulo node:worker_threads
permite o uso de threads que executam JavaScript em paralelo. Para acessá-lo:
const worker = require('node:worker_threads')
Trabalhadores (threads) são úteis para executar operações JavaScript intensivas em CPU. Eles não ajudam muito com trabalho intensivo em E/S. As operações de E/S assíncronas integradas do Node.js são mais eficientes do que os Workers podem ser.
Ao contrário de child_process
ou cluster
, worker_threads
podem compartilhar memória. Eles fazem isso transferindo instâncias ArrayBuffer
ou compartilhando instâncias 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))
}
O exemplo acima gera uma thread Worker para cada chamada parseJSAsync()
. Na prática, use um pool de Workers para esses tipos de tarefas. Caso contrário, a sobrecarga de criar Workers provavelmente excederá seu benefício.
Ao implementar um pool de trabalhadores, use a API AsyncResource
para informar as ferramentas de diagnóstico (por exemplo, para fornecer rastros de pilha assíncronos) sobre a correlação entre tarefas e seus resultados. Veja "Usando AsyncResource
para um pool de threads Worker
" na documentação async_hooks
para um exemplo de implementação.
Threads de trabalhador herdam opções não específicas do processo por padrão. Consulte Opções do construtor Worker
para saber como personalizar as opções de thread de trabalhador, especificamente as opções argv
e execArgv
.
worker.getEnvironmentData(key)
[Histórico]
Versão | Alterações |
---|---|
v17.5.0, v16.15.0 | Não é mais experimental. |
v15.12.0, v14.18.0 | Adicionado em: v15.12.0, v14.18.0 |
key
<any> Qualquer valor JavaScript arbitrário e clonável que possa ser usado como chave de um <Map>.- Retorna: <any>
Dentro de uma thread worker, worker.getEnvironmentData()
retorna um clone dos dados passados para worker.setEnvironmentData()
da thread de geração. Cada novo Worker
recebe automaticamente sua própria cópia dos dados do ambiente.
const { Worker, isMainThread, setEnvironmentData, getEnvironmentData } = require('node:worker_threads')
if (isMainThread) {
setEnvironmentData('Hello', 'World!')
const worker = new Worker(__filename)
} else {
console.log(getEnvironmentData('Hello')) // Imprime 'World!'.
}
worker.isMainThread
Adicionado em: v10.5.0
É true
se este código não estiver sendo executado dentro de uma thread Worker
.
const { Worker, isMainThread } = require('node:worker_threads')
if (isMainThread) {
// Isso recarrega o arquivo atual dentro de uma instância Worker.
new Worker(__filename)
} else {
console.log('Dentro do Worker!')
console.log(isMainThread) // Imprime 'false'.
}
worker.markAsUntransferable(object)
Adicionado em: v14.5.0, v12.19.0
object
<any> Qualquer valor JavaScript arbitrário.
Marca um objeto como não transferível. Se object
ocorrer na lista de transferência de uma chamada port.postMessage()
, um erro será lançado. Esta é uma operação sem efeito se object
for um valor primitivo.
Em particular, isso faz sentido para objetos que podem ser clonados, em vez de transferidos, e que são usados por outros objetos do lado do remetente. Por exemplo, o Node.js marca os ArrayBuffer
s que ele usa para seu pool Buffer
com isso.
Esta operação não pode ser desfeita.
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 {
// Isso lançará um erro, porque pooledBuffer não é transferível.
port1.postMessage(typedArray1, [typedArray1.buffer])
} catch (error) {
// error.name === 'DataCloneError'
}
// A linha a seguir imprime o conteúdo de typedArray1 -- ele ainda possui
// sua memória e não foi transferido. Sem
// `markAsUntransferable()`, isso imprimiria um Uint8Array vazio e a
// chamada postMessage teria sido bem-sucedida.
// typedArray2 também está intacto.
console.log(typedArray1)
console.log(typedArray2)
Não existe um equivalente a esta API em navegadores.
worker.isMarkedAsUntransferable(object)
Adicionado em: v21.0.0
Verifica se um objeto está marcado como não transferível com markAsUntransferable()
.
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads')
const pooledBuffer = new ArrayBuffer(8)
markAsUntransferable(pooledBuffer)
isMarkedAsUntransferable(pooledBuffer) // Retorna true.
Não existe equivalente a esta API em navegadores.
worker.markAsUncloneable(object)
Adicionado em: v23.0.0
object
<any> Qualquer valor JavaScript arbitrário.
Marca um objeto como não clonável. Se object
for usado como message
em uma chamada port.postMessage()
, um erro será lançado. Esta é uma operação sem efeito se object
for um valor primitivo.
Isso não tem efeito em ArrayBuffer
, ou qualquer objeto semelhante a Buffer
.
Esta operação não pode ser desfeita.
const { markAsUncloneable } = require('node:worker_threads')
const anyObject = { foo: 'bar' }
markAsUncloneable(anyObject)
const { port1 } = new MessageChannel()
try {
// Isso lançará um erro, porque anyObject não é clonável.
port1.postMessage(anyObject)
} catch (error) {
// error.name === 'DataCloneError'
}
Não existe equivalente a esta API em navegadores.
worker.moveMessagePortToContext(port, contextifiedSandbox)
Adicionado em: v11.13.0
port
<MessagePort> A porta de mensagem a ser transferida.contextifiedSandbox
<Object> Um objeto contextizado como retornado pelo métodovm.createContext()
.- Retorna: <MessagePort>
Transfere uma MessagePort
para um contexto vm
diferente. O objeto port
original é tornado inutilizável, e a instância MessagePort
retornada toma seu lugar.
A MessagePort
retornada é um objeto no contexto de destino e herda da sua classe global Object
. Os objetos passados para o listener port.onmessage()
também são criados no contexto de destino e herdam da sua classe global Object
.
Entretanto, a MessagePort
criada não herda mais de EventTarget
, e somente port.onmessage()
pode ser usado para receber eventos usando-a.
worker.parentPort
Adicionado em: v10.5.0
Se esta thread for uma Worker
, esta é uma MessagePort
permitindo comunicação com a thread pai. Mensagens enviadas usando parentPort.postMessage()
estão disponíveis na thread pai usando worker.on('message')
, e mensagens enviadas da thread pai usando worker.postMessage()
estão disponíveis nesta thread usando 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) // Imprime 'Olá, mundo!'.
})
worker.postMessage('Olá, mundo!')
} else {
// Quando uma mensagem da thread pai é recebida, envie-a de volta:
parentPort.once('message', message => {
parentPort.postMessage(message)
})
}
worker.postMessageToThread(threadId, value[, transferList][, timeout])
Adicionado em: v22.5.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1.1 - Desenvolvimento ativo
threadId
<número> O ID da thread de destino. Se o ID da thread for inválido, um erroERR_WORKER_MESSAGING_FAILED
será lançado. Se o ID da thread de destino for o ID da thread atual, um erroERR_WORKER_MESSAGING_SAME_THREAD
será lançado.value
<qualquer> O valor a ser enviado.transferList
<Object[]> Se um ou mais objetos do tipoMessagePort
forem passados emvalue
, umatransferList
é necessária para esses itens ouERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
será lançado. Vejaport.postMessage()
para mais informações.timeout
<número> Tempo para esperar que a mensagem seja entregue em milissegundos. Por padrão éundefined
, o que significa esperar para sempre. Se a operação expirar, um erroERR_WORKER_MESSAGING_TIMEOUT
será lançado.- Retorna: <Promise> Uma promise que é cumprida se a mensagem foi processada com sucesso pela thread de destino.
Envia um valor para outra worker, identificada pelo seu ID de thread.
Se a thread de destino não tiver um ouvinte para o evento workerMessage
, a operação lançará um erro ERR_WORKER_MESSAGING_FAILED
.
Se a thread de destino lançou um erro ao processar o evento workerMessage
, a operação lançará um erro ERR_WORKER_MESSAGING_ERRORED
.
Este método deve ser usado quando a thread de destino não for o pai ou filho direto da thread atual. Se as duas threads forem pai-filhos, use require('node:worker_threads').parentPort.postMessage()
e worker.postMessage()
para permitir que as threads se comuniquem.
O exemplo abaixo mostra o uso de postMessageToThread
: ele cria 10 threads aninhadas, a última tentará se comunicar com a thread principal.
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)
[Histórico]
Versão | Alterações |
---|---|
v15.12.0 | O argumento port agora também pode se referir a um BroadcastChannel . |
v12.3.0 | Adicionado em: v12.3.0 |
port
<MessagePort> | <BroadcastChannel>- Retorna: <Object> | <undefined>
Recebe uma única mensagem de um determinado MessagePort
. Se nenhuma mensagem estiver disponível, undefined
é retornado; caso contrário, um objeto com uma única propriedade message
que contém a carga útil da mensagem, correspondente à mensagem mais antiga na fila do MessagePort
.
const { MessageChannel, receiveMessageOnPort } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
port1.postMessage({ hello: 'world' })
console.log(receiveMessageOnPort(port2))
// Imprime: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2))
// Imprime: undefined
Quando esta função é usada, nenhum evento 'message'
é emitido e o listener onmessage
não é invocado.
worker.resourceLimits
Adicionado em: v13.2.0, v12.16.0
Fornece o conjunto de restrições de recursos do mecanismo JS dentro desta thread Worker. Se a opção resourceLimits
foi passada para o construtor Worker
, isso corresponde aos seus valores.
Se isso for usado na thread principal, seu valor é um objeto vazio.
worker.SHARE_ENV
Adicionado em: v11.14.0
Um valor especial que pode ser passado como a opção env
do construtor Worker
, para indicar que a thread atual e a thread Worker devem compartilhar acesso de leitura e escrita ao mesmo conjunto de variáveis de ambiente.
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) // Imprime 'foo'.
})
worker.setEnvironmentData(key[, value])
[Histórico]
Versão | Alterações |
---|---|
v17.5.0, v16.15.0 | Não mais experimental. |
v15.12.0, v14.18.0 | Adicionada em: v15.12.0, v14.18.0 |
key
<any> Qualquer valor JavaScript arbitrário e clonável que pode ser usado como uma chave <Map>.value
<any> Qualquer valor JavaScript arbitrário e clonável que será clonado e passado automaticamente para todas as novas instânciasWorker
. Sevalue
for passado comoundefined
, qualquer valor previamente definido para akey
será deletado.
A API worker.setEnvironmentData()
define o conteúdo de worker.getEnvironmentData()
na thread atual e em todas as novas instâncias Worker
geradas a partir do contexto atual.
worker.threadId
Adicionado em: v10.5.0
Um identificador inteiro para a thread atual. No objeto worker correspondente (se houver algum), ele está disponível como worker.threadId
. Este valor é único para cada instância Worker
dentro de um único processo.
worker.workerData
Adicionado em: v10.5.0
Um valor JavaScript arbitrário que contém uma cópia dos dados passados para o construtor Worker
desta thread.
Os dados são clonados como se estivesse usando postMessage()
, de acordo com o algoritmo de clonagem estruturada HTML.
const { Worker, isMainThread, workerData } = require('node:worker_threads')
if (isMainThread) {
const worker = new Worker(__filename, { workerData: 'Olá, mundo!' })
} else {
console.log(workerData) // Imprime 'Olá, mundo!'.
}
Classe: BroadcastChannel extends EventTarget
[Histórico]
Versão | Mudanças |
---|---|
v18.0.0 | Não mais experimental. |
v15.4.0 | Adicionada em: v15.4.0 |
Instâncias de BroadcastChannel
permitem comunicação assíncrona de um-para-muitos com todas as outras instâncias BroadcastChannel
vinculadas ao mesmo nome de canal.
'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('Olá de cada worker')
bc.close()
}
new BroadcastChannel(name)
Adicionado em: v15.4.0
name
<qualquer> O nome do canal para conectar. Qualquer valor JavaScript que pode ser convertido em uma string usando${name}
é permitido.
broadcastChannel.close()
Adicionado em: v15.4.0
Fecha a conexão BroadcastChannel
.
broadcastChannel.onmessage
Adicionado em: v15.4.0
- Tipo: <Função> Invoca com um único argumento
MessageEvent
quando uma mensagem é recebida.
broadcastChannel.onmessageerror
Adicionado em: v15.4.0
- Tipo: <Function> Invoca quando uma mensagem recebida não pode ser desserializada.
broadcastChannel.postMessage(message)
Adicionado em: v15.4.0
message
<any> Qualquer valor JavaScript clonável.
broadcastChannel.ref()
Adicionado em: v15.4.0
Oposto de unref()
. Chamar ref()
em um BroadcastChannel previamente unref()
ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se a porta estiver ref()
ed, chamar ref()
novamente não terá efeito.
broadcastChannel.unref()
Adicionado em: v15.4.0
Chamar unref()
em um BroadcastChannel permite que a thread saia se este for o único manipulador ativo no sistema de eventos. Se o BroadcastChannel já estiver unref()
ed, chamar unref()
novamente não terá efeito.
Classe: MessageChannel
Adicionado em: v10.5.0
Instâncias da classe worker.MessageChannel
representam um canal de comunicação bidirecional assíncrono. O MessageChannel
não possui métodos próprios. new MessageChannel()
retorna um objeto com propriedades port1
e port2
, que se referem a instâncias MessagePort
vinculadas.
const { MessageChannel } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
port1.on('message', message => console.log('received', message))
port2.postMessage({ foo: 'bar' })
// Imprime: received { foo: 'bar' } do listener `port1.on('message')`
Classe: MessagePort
[Histórico]
Versão | Alterações |
---|---|
v14.7.0 | Esta classe agora herda de EventTarget em vez de EventEmitter . |
v10.5.0 | Adicionada em: v10.5.0 |
- Extende: <EventTarget>
Instâncias da classe worker.MessagePort
representam uma extremidade de um canal de comunicação bidirecional assíncrono. Pode ser usado para transferir dados estruturados, regiões de memória e outros MessagePort
s entre diferentes Worker
s.
Esta implementação corresponde aos MessagePort do navegadors.
Evento: 'close'
Adicionado em: v10.5.0
O evento 'close'
é emitido assim que um dos lados do canal for desconectado.
const { MessageChannel } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
// Imprime:
// foobar
// closed!
port2.on('message', message => console.log(message))
port2.on('close', () => console.log('closed!'))
port1.postMessage('foobar')
port1.close()
Evento: 'message'
Adicionado em: v10.5.0
value
<any> O valor transmitido
O evento 'message'
é emitido para qualquer mensagem recebida, contendo a entrada clonada de port.postMessage()
.
Os ouvintes deste evento recebem um clone do parâmetro value
como passado para postMessage()
e nenhum outro argumento.
Evento: 'messageerror'
Adicionado em: v14.5.0, v12.19.0
error
<Error> Um objeto Error
O evento 'messageerror'
é emitido quando a desserialização de uma mensagem falha.
Atualmente, este evento é emitido quando ocorre um erro ao instanciar o objeto JS postado no lado receptor. Tais situações são raras, mas podem acontecer, por exemplo, quando certos objetos da API Node.js são recebidos em um vm.Context
(onde as APIs Node.js estão atualmente indisponíveis).
port.close()
Adicionado em: v10.5.0
Desabilita o envio posterior de mensagens em qualquer lado da conexão. Este método pode ser chamado quando não houver mais comunicação através desta MessagePort
.
O evento 'close'
é emitido em ambas as instâncias MessagePort
que fazem parte do canal.
port.postMessage(value[, transferList])
[Histórico]
Versão | Alterações |
---|---|
v21.0.0 | Um erro é lançado quando um objeto não transferível está na lista de transferência. |
v15.6.0 | Adicionado X509Certificate à lista de tipos clonáveis. |
v15.0.0 | Adicionado CryptoKey à lista de tipos clonáveis. |
v15.14.0, v14.18.0 | Adicionar 'BlockList' à lista de tipos clonáveis. |
v15.9.0, v14.18.0 | Adicionar tipos 'Histogram' à lista de tipos clonáveis. |
v14.5.0, v12.19.0 | Adicionado KeyObject à lista de tipos clonáveis. |
v14.5.0, v12.19.0 | Adicionado FileHandle à lista de tipos transferíveis. |
v10.5.0 | Adicionado em: v10.5.0 |
value
<any>transferList
<Object[]>
Envia um valor JavaScript para o lado receptor deste canal. value
é transferido de uma forma compatível com o algoritmo de clonagem estruturada HTML.
Em particular, as diferenças significativas para JSON
são:
value
pode conter referências circulares.value
pode conter instâncias de tipos JS embutidos comoRegExp
s,BigInt
s,Map
s,Set
s, etc.value
pode conter arrays tipados, usandoArrayBuffer
s eSharedArrayBuffer
s.value
pode conter instânciasWebAssembly.Module
.value
não pode conter objetos nativos (suportados por C++) além de:
const { MessageChannel } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
port1.on('message', message => console.log(message))
const circularData = {}
circularData.foo = circularData
// Imprime: { foo: [Circular] }
port2.postMessage(circularData)
transferList
pode ser uma lista de objetos ArrayBuffer
, MessagePort
e FileHandle
. Após a transferência, eles não são mais utilizáveis no lado de envio do canal (mesmo que não estejam contidos em value
). Ao contrário dos processos filhos, a transferência de handles como sockets de rede não é atualmente suportada.
Se value
contiver instâncias SharedArrayBuffer
, elas são acessíveis de qualquer thread. Elas não podem ser listadas em transferList
.
value
ainda pode conter instâncias ArrayBuffer
que não estão em transferList
; nesse caso, a memória subjacente é copiada em vez de movida.
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])
// Isso posta uma cópia de `uint8Array`:
port2.postMessage(uint8Array)
// Isso não copia dados, mas torna `uint8Array` inutilizável:
port2.postMessage(uint8Array, [uint8Array.buffer])
// A memória para `sharedUint8Array` é acessível tanto do
// original quanto da cópia recebida por `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4))
port2.postMessage(sharedUint8Array)
// Isso transfere uma porta de mensagem recém-criada para o receptor.
// Isso pode ser usado, por exemplo, para criar canais de comunicação entre
// múltiplas threads `Worker` que são filhos da mesma thread pai.
const otherChannel = new MessageChannel()
port2.postMessage({ port: otherChannel.port1 }, [otherChannel.port1])
O objeto de mensagem é clonado imediatamente e pode ser modificado após a postagem sem efeitos colaterais.
Para mais informações sobre os mecanismos de serialização e desserialização por trás desta API, consulte a API de serialização do módulo node:v8
.
Considerações ao transferir TypedArrays e Buffers
Todas as instâncias de TypedArray
e Buffer
são visualizações de um ArrayBuffer
subjacente. Ou seja, é o ArrayBuffer
que realmente armazena os dados brutos, enquanto os objetos TypedArray
e Buffer
fornecem uma maneira de visualizar e manipular os dados. É possível e comum que várias visualizações sejam criadas sobre a mesma instância de ArrayBuffer
. É necessário ter muito cuidado ao usar uma lista de transferência para transferir um ArrayBuffer
, pois isso faz com que todas as instâncias de TypedArray
e Buffer
que compartilham o mesmo ArrayBuffer
se tornem inutilizáveis.
const ab = new ArrayBuffer(10)
const u1 = new Uint8Array(ab)
const u2 = new Uint16Array(ab)
console.log(u2.length) // imprime 5
port.postMessage(u1, [u1.buffer])
console.log(u2.length) // imprime 0
Para instâncias Buffer
, especificamente, se o ArrayBuffer
subjacente pode ser transferido ou clonado depende inteiramente de como as instâncias foram criadas, o que muitas vezes não pode ser determinado de forma confiável.
Um ArrayBuffer
pode ser marcado com markAsUntransferable()
para indicar que ele deve sempre ser clonado e nunca transferido.
Dependendo de como uma instância Buffer
foi criada, ela pode ou não possuir seu ArrayBuffer
subjacente. Um ArrayBuffer
não deve ser transferido a menos que se saiba que a instância Buffer
o possui. Em particular, para Buffers
criados a partir do pool interno Buffer
(usando, por exemplo, Buffer.from()
ou Buffer.allocUnsafe()
), transferir eles não é possível e eles são sempre clonados, o que envia uma cópia de todo o pool Buffer
. Esse comportamento pode trazer um uso de memória mais alto e preocupações de segurança imprevistas.
Veja Buffer.allocUnsafe()
para mais detalhes sobre o pool Buffer
.
Os ArrayBuffers
para instâncias Buffer
criadas usando Buffer.alloc()
ou Buffer.allocUnsafeSlow()
podem sempre ser transferidos, mas isso torna todas as outras visualizações existentes desses ArrayBuffers
inutilizáveis.
Considerações ao clonar objetos com protótipos, classes e acessores
Como a clonagem de objetos usa o algoritmo de clone estruturado HTML, propriedades não enumeráveis, acessores de propriedade e protótipos de objetos não são preservados. Em particular, objetos Buffer
serão lidos como Uint8Array
simples do lado receptor, e instâncias de classes JavaScript serão clonadas como objetos JavaScript simples.
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())
// Imprime: { c: 3 }
Essa limitação se estende a muitos objetos embutidos, como o objeto global URL
:
const { port1, port2 } = new MessageChannel()
port1.onmessage = ({ data }) => console.log(data)
port2.postMessage(new URL('https://example.org'))
// Imprime: { }
port.hasRef()
Adicionado em: v18.1.0, v16.17.0
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1 - Experimental
- Retorna: <boolean>
Se verdadeiro, o objeto MessagePort
manterá o loop de eventos do Node.js ativo.
port.ref()
Adicionado em: v10.5.0
Oposto de unref()
. Chamar ref()
em uma porta previamente unref()
ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se a porta estiver ref()
ed, chamar ref()
novamente não tem efeito.
Se os ouvintes forem anexados ou removidos usando .on('message')
, a porta é ref()
ed e unref()
ed automaticamente dependendo se os ouvintes para o evento existem.
port.start()
Adicionado em: v10.5.0
Inicia o recebimento de mensagens neste MessagePort
. Ao usar esta porta como um emissor de eventos, isso é chamado automaticamente assim que os ouvintes de 'message'
são anexados.
Este método existe para paridade com a API MessagePort
da Web. No Node.js, só é útil para ignorar mensagens quando nenhum ouvinte de eventos está presente. O Node.js também diverge em seu tratamento de .onmessage
. Definir isso chama automaticamente .start()
, mas desdefini-lo permite que as mensagens sejam enfileiradas até que um novo manipulador seja definido ou a porta seja descartada.
port.unref()
Adicionado em: v10.5.0
Chamar unref()
em uma porta permite que a thread saia se esta for o único manipulador ativo no sistema de eventos. Se a porta já estiver unref()
, chamar unref()
novamente não terá efeito.
Se ouvintes forem anexados ou removidos usando .on('message')
, a porta é ref()
e unref()
automaticamente, dependendo se existem ouvintes para o evento.
Classe: Worker
Adicionado em: v10.5.0
- Extende: <EventEmitter>
A classe Worker
representa uma thread de execução JavaScript independente. A maioria das APIs do Node.js está disponível dentro dela.
Diferenças notáveis dentro de um ambiente Worker são:
- Os fluxos
process.stdin
,process.stdout
eprocess.stderr
podem ser redirecionados pela thread pai. - A propriedade
require('node:worker_threads').isMainThread
é definida comofalse
. - A porta de mensagem
require('node:worker_threads').parentPort
está disponível. process.exit()
não interrompe todo o programa, apenas a thread única, eprocess.abort()
não está disponível.process.chdir()
e os métodosprocess
que definem IDs de grupo ou usuário não estão disponíveis.process.env
é uma cópia das variáveis de ambiente da thread pai, a menos que especificado de outra forma. As alterações em uma cópia não são visíveis em outras threads e não são visíveis para complementos nativos (a menos queworker.SHARE_ENV
seja passado como a opçãoenv
para o construtorWorker
). No Windows, ao contrário da thread principal, uma cópia das variáveis de ambiente opera de maneira sensível a maiúsculas e minúsculas.process.title
não pode ser modificado.- Os sinais não são entregues por meio de
process.on('...')
. - A execução pode parar a qualquer momento como resultado da invocação de
worker.terminate()
. - Os canais IPC de processos pai não são acessíveis.
- O módulo
trace_events
não é suportado. - Complementos nativos só podem ser carregados de várias threads se atenderem a determinadas condições.
Criar instâncias Worker
dentro de outros Worker
s é possível.
Como Web Workers e o módulo node:cluster
, a comunicação bidirecional pode ser alcançada por meio da passagem de mensagens entre threads. Internamente, um Worker
possui um par embutido de MessagePort
s que já estão associados um ao outro quando o Worker
é criado. Embora o objeto MessagePort
do lado pai não seja exposto diretamente, suas funcionalidades são expostas por meio de worker.postMessage()
e o evento worker.on('message')
no objeto Worker
para a thread pai.
Para criar canais de mensagens personalizados (o que é recomendado em vez de usar o canal global padrão porque facilita a separação de preocupações), os usuários podem criar um objeto MessageChannel
em qualquer thread e passar um dos MessagePort
s nesse MessageChannel
para a outra thread por meio de um canal preexistente, como o global.
Veja port.postMessage()
para obter mais informações sobre como as mensagens são passadas e que tipo de valores JavaScript podem ser transportados com sucesso pela barreira de thread.
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])
[Histórico]
Versão | Alterações |
---|---|
v19.8.0, v18.16.0 | Adicionou suporte para uma opção name , que permite adicionar um nome ao título do worker para depuração. |
v14.9.0 | O parâmetro filename pode ser um objeto URL WHATWG usando o protocolo data: . |
v14.9.0 | A opção trackUnmanagedFds foi definida como true por padrão. |
v14.6.0, v12.19.0 | A opção trackUnmanagedFds foi introduzida. |
v13.13.0, v12.17.0 | A opção transferList foi introduzida. |
v13.12.0, v12.17.0 | O parâmetro filename pode ser um objeto URL WHATWG usando o protocolo file: . |
v13.4.0, v12.16.0 | A opção argv foi introduzida. |
v13.2.0, v12.16.0 | A opção resourceLimits foi introduzida. |
v10.5.0 | Adicionada em: v10.5.0 |
filename
<string> | <URL> O caminho para o script principal ou módulo do Worker. Deve ser um caminho absoluto ou um caminho relativo (ou seja, relativo ao diretório de trabalho atual) começando com./
ou../
, ou um objetoURL
WHATWG usando o protocolofile:
oudata:
. Ao usar umaURL data:
, os dados são interpretados com base no tipo MIME usando o carregador de módulo ECMAScript. Seoptions.eval
fortrue
, esta é uma string contendo código JavaScript em vez de um caminho.options
<Object>argv
<any[]> Lista de argumentos que seriam convertidos em string e anexados aprocess.argv
no worker. Isso é muito semelhante aoworkerData
, mas os valores estão disponíveis noprocess.argv
global como se fossem passados como opções de CLI para o script.env
<Object> Se definido, especifica o valor inicial deprocess.env
dentro da thread Worker. Como um valor especial,worker.SHARE_ENV
pode ser usado para especificar que a thread pai e a thread filho devem compartilhar suas variáveis de ambiente; nesse caso, as alterações no objetoprocess.env
de uma thread afetam a outra thread também. Padrão:process.env
.eval
<boolean> Setrue
e o primeiro argumento for umastring
, interpreta o primeiro argumento do construtor como um script que é executado assim que o worker estiver online.execArgv
<string[]> Lista de opções de CLI do Node passadas para o worker. Opções V8 (como--max-old-space-size
) e opções que afetam o processo (como--title
) não são suportadas. Se definido, isso é fornecido comoprocess.execArgv
dentro do worker. Por padrão, as opções são herdadas da thread pai.stdin
<boolean> Se isso for definido comotrue
, entãoworker.stdin
fornece um fluxo gravável cujo conteúdo aparece comoprocess.stdin
dentro do Worker. Por padrão, nenhum dado é fornecido.stdout
<boolean> Se isso for definido comotrue
, entãoworker.stdout
não é automaticamente canalizado paraprocess.stdout
no pai.stderr
<boolean> Se isso for definido comotrue
, entãoworker.stderr
não é automaticamente canalizado paraprocess.stderr
no pai.workerData
<any> Qualquer valor JavaScript que é clonado e disponibilizado comorequire('node:worker_threads').workerData
. A clonagem ocorre como descrito no algoritmo de clonagem estruturada HTML, e um erro é lançado se o objeto não puder ser clonado (por exemplo, porque contémfunction
s).trackUnmanagedFds
<boolean> Se isso for definido comotrue
, o Worker rastreia descritores de arquivos brutos gerenciados por meio defs.open()
efs.close()
, e os fecha quando o Worker sair, semelhante a outros recursos como sockets de rede ou descritores de arquivos gerenciados por meio da APIFileHandle
. Esta opção é herdada automaticamente por todos osWorker
s aninhados. Padrão:true
.transferList
<Object[]> Se um ou mais objetos do tipoMessagePort
forem passados emworkerData
, umatransferList
é necessária para esses itens ouERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
é lançado. Vejaport.postMessage()
para mais informações.resourceLimits
<Object> Um conjunto opcional de limites de recursos para a nova instância do mecanismo JS. Alcançar esses limites leva ao encerramento da instânciaWorker
. Esses limites afetam apenas o mecanismo JS e nenhum dado externo, incluindo nenhumArrayBuffer
. Mesmo que esses limites sejam definidos, o processo ainda pode ser abortado se encontrar uma situação global de falta de memória.maxOldGenerationSizeMb
<number> O tamanho máximo do heap principal em MB. Se o argumento da linha de comando--max-old-space-size
estiver definido, ele substitui esta configuração.maxYoungGenerationSizeMb
<number> O tamanho máximo de um espaço de heap para objetos criados recentemente. Se o argumento da linha de comando--max-semi-space-size
estiver definido, ele substitui esta configuração.codeRangeSizeMb
<number> O tamanho de um intervalo de memória pré-alocado usado para código gerado.stackSizeMb
<number> O tamanho máximo de pilha padrão para a thread. Valores pequenos podem levar a instâncias de Worker inutilizáveis. Padrão:4
.name
<string> Umname
opcional a ser anexado ao título do worker para fins de depuração/identificação, tornando o título final como[worker ${id}] ${name}
. Padrão:''
.
Evento: 'error'
Adicionado em: v10.5.0
err
<Error>
O evento 'error'
é emitido se a thread worker lançar uma exceção não capturada. Nesse caso, a worker é encerrada.
Evento: 'exit'
Adicionado em: v10.5.0
exitCode
<inteiro>
O evento 'exit'
é emitido assim que a worker para. Se a worker foi encerrada chamando process.exit()
, o parâmetro exitCode
é o código de saída passado. Se a worker foi encerrada, o parâmetro exitCode
é 1
.
Este é o evento final emitido por qualquer instância Worker
.
Evento: 'message'
Adicionado em: v10.5.0
value
<qualquer> O valor transmitido
O evento 'message'
é emitido quando a thread worker invocou require('node:worker_threads').parentPort.postMessage()
. Veja o evento port.on('message')
para mais detalhes.
Todas as mensagens enviadas da thread worker são emitidas antes do evento 'exit'
ser emitido no objeto Worker
.
Evento: 'messageerror'
Adicionado em: v14.5.0, v12.19.0
error
<Error> Um objeto Error
O evento 'messageerror'
é emitido quando a desserialização de uma mensagem falha.
Evento: 'online'
Adicionado em: v10.5.0
O evento 'online'
é emitido quando a thread worker começou a executar o código JavaScript.
worker.getHeapSnapshot([options])
[Histórico]
Versão | Alterações |
---|---|
v19.1.0 | Suporte a opções para configurar o snapshot do heap. |
v13.9.0, v12.17.0 | Adicionada em: v13.9.0, v12.17.0 |
options
<Objeto>exposeInternals
<booleano> Se verdadeiro, expõe elementos internos no snapshot do heap. Padrão:false
.exposeNumericValues
<booleano> Se verdadeiro, expõe valores numéricos em campos artificiais. Padrão:false
.
Retorna: <Promise> Uma promise para um fluxo legível contendo um snapshot do heap V8
Retorna um fluxo legível para um snapshot V8 do estado atual da Worker. Veja v8.getHeapSnapshot()
para mais detalhes.
Se a thread Worker não estiver mais em execução, o que pode ocorrer antes do evento 'exit'
ser emitido, a Promise
retornada é rejeitada imediatamente com um erro ERR_WORKER_NOT_RUNNING
.
worker.performance
Adicionado em: v15.1.0, v14.17.0, v12.22.0
Um objeto que pode ser usado para consultar informações de desempenho de uma instância de worker. Similar a perf_hooks.performance
.
performance.eventLoopUtilization([utilization1[, utilization2]])
Adicionado em: v15.1.0, v14.17.0, v12.22.0
utilization1
<Object> O resultado de uma chamada anterior aeventLoopUtilization()
.utilization2
<Object> O resultado de uma chamada anterior aeventLoopUtilization()
antes deutilization1
.- Retorna: <Object>
A mesma chamada que perf_hooks
eventLoopUtilization()
, exceto que os valores da instância do worker são retornados.
Uma diferença é que, ao contrário da thread principal, a inicialização dentro de um worker é feita dentro do loop de eventos. Portanto, a utilização do loop de eventos está imediatamente disponível assim que o script do worker começa a execução.
Um tempo idle
que não aumenta não indica que o worker está preso na inicialização. Os exemplos a seguir mostram como a vida útil inteira do worker nunca acumula nenhum tempo idle
, mas ainda é capaz de processar mensagens.
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)
A utilização do loop de eventos de um worker está disponível somente após o evento 'online'
ser emitido, e se chamado antes disso, ou após o evento 'exit'
, então todas as propriedades terão o valor 0
.
worker.postMessage(value[, transferList])
Adicionado em: v10.5.0
value
<any>transferList
<Object[]>
Envia uma mensagem para o worker que é recebida via require('node:worker_threads').parentPort.on('message')
. Veja port.postMessage()
para mais detalhes.
worker.ref()
Adicionado em: v10.5.0
O oposto de unref()
, chamar ref()
em um worker previamente unref()
ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se o worker for ref()
ed, chamar ref()
novamente não tem efeito.
worker.resourceLimits
Adicionado em: v13.2.0, v12.16.0
Fornece o conjunto de restrições de recursos do mecanismo JS para esta thread Worker. Se a opção resourceLimits
foi passada para o construtor Worker
, isto corresponde aos seus valores.
Se o worker parou, o valor retornado é um objeto vazio.
worker.stderr
Adicionado em: v10.5.0
Este é um fluxo legível que contém dados escritos para process.stderr
dentro da thread worker. Se stderr: true
não foi passado para o construtor Worker
, então os dados são canalizados para o fluxo process.stderr
da thread pai.
worker.stdin
Adicionado em: v10.5.0
Se stdin: true
foi passado para o construtor Worker
, este é um fluxo gravável. Os dados escritos neste fluxo ficarão disponíveis na thread worker como process.stdin
.
worker.stdout
Adicionado em: v10.5.0
Este é um fluxo legível que contém dados escritos para process.stdout
dentro da thread worker. Se stdout: true
não foi passado para o construtor Worker
, então os dados são canalizados para o fluxo process.stdout
da thread pai.
worker.terminate()
[Histórico]
Versão | Alterações |
---|---|
v12.5.0 | Esta função agora retorna uma Promise. Passar um callback está depreciado e era inútil até esta versão, pois o Worker era realmente terminado sincronicamente. A terminação agora é uma operação totalmente assíncrona. |
v10.5.0 | Adicionada em: v10.5.0 |
- Retorna: <Promise>
Pare toda a execução JavaScript na thread worker o mais rápido possível. Retorna uma Promise para o código de saída que é cumprida quando o evento 'exit'
é emitido.
worker.threadId
Adicionado em: v10.5.0
Um identificador inteiro para a thread referenciada. Dentro da thread worker, está disponível como require('node:worker_threads').threadId
. Este valor é único para cada instância Worker
dentro de um único processo.
worker.unref()
Adicionado em: v10.5.0
Chamar unref()
em um worker permite que a thread saia se esta for a única alça ativa no sistema de eventos. Se o worker já estiver unref()
ed, chamar unref()
novamente não terá efeito.
Notas
Bloqueio síncrono de stdio
Worker
s utilizam passagem de mensagens via <MessagePort> para implementar interações com stdio
. Isso significa que a saída stdio
originada de um Worker
pode ser bloqueada por código síncrono na extremidade receptora que está bloqueando o loop de eventos do 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')
}
Iniciando threads worker a partir de scripts de pré-carregamento
Tome cuidado ao iniciar threads worker a partir de scripts de pré-carregamento (scripts carregados e executados usando a flag de linha de comando -r
). A menos que a opção execArgv
seja definida explicitamente, novas threads Worker herdam automaticamente as flags de linha de comando do processo em execução e pré-carregarão os mesmos scripts de pré-carregamento que a thread principal. Se o script de pré-carregamento iniciar incondicionalmente uma thread worker, cada thread gerada gerará outra até que o aplicativo trave.