Spec-Zone.ru › Node.js 20 LTS

Потоки рабочих нитей

Стабильность: 2 - Стабильно

Исходный код: lib/worker_threads.js

Модуль node:worker_threads позволяет использовать потоки, которые выполняют JavaScript параллельно. Чтобы получить к нему доступ:

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

Рабочие потоки (нити) полезны для выполнения ресурсоёмких операций JavaScript. Они не очень помогают с операциями ввода-вывода. Встроенные асинхронные операции ввода-вывода Node.js более эффективны, чем могут быть рабочие потоки.

В отличие от child_process или cluster, worker_threads могут совместно использовать память. Они делают это, передавая экземпляры ArrayBuffer или совместно используя экземпляры SharedArrayBuffer.

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

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script,
      });
      worker.on('message', resolve);
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0)
          reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
} copy

В приведённом выше примере для каждого вызова parseJSAsync() создаётся отдельный поток рабочего. На практике для таких задач следует использовать пул рабочих потоков. В противном случае накладные расходы на создание рабочих потоков, вероятно, превысят их преимущества.

При реализации пула рабочих потоков используйте API AsyncResource, чтобы сообщить средствам диагностики (например, для предоставления асинхронных стеков вызовов) о корреляции между задачами и их результатами. См. "Использование AsyncResource для пула потоков рабочих Worker" в документации async_hooks для примера реализации.

Потоки рабочих нитей по умолчанию наследуют параметры, не зависящие от процесса. Обратитесь к Worker constructor options, чтобы узнать, как настроить параметры потоков рабочих нитей, в частности параметры argv и execArgv.

worker.getEnvironmentData(key)

История
Версия Изменения
v17.5.0, v16.15.0

Больше не экспериментальный.

v15.12.0, v14.18.0

Добавлен в: v15.12.0, v14.18.0

  • key <любой> Любое произвольное, клонируемое значение JavaScript, которое может использоваться в качестве ключа <Map>.
  • Возвращает: <любой>

В потоке рабочего внутри worker.getEnvironmentData() возвращает копию данных, переданных в порождающем потоке worker.setEnvironmentData(). Каждый новый Worker автоматически получает свою собственную копию данных среды.

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

if (isMainThread) {
  setEnvironmentData('Hello', 'World!');
  const worker = new Worker(__filename);
} else {
  console.log(getEnvironmentData('Hello'));  // Prints 'World!'.
} copy

worker.isMainThread

Добавлен в: v10.5.0
  • <boolean>

Является true если этот код не выполняется внутри потока Worker.

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

worker.markAsUntransferable(object)

Добавлен в: v14.5.0, v12.19.0

Отметить объект как непередаваемый. Если object появляется в списке передачи вызова port.postMessage(), он игнорируется.

В частности, это имеет смысл для объектов, которые могут быть клонированы, а не переданы, и которые используются другими объектами на стороне отправки. Например, Node.js помечает ArrayBuffer используемые им для пула Buffer пула этим способом.

Это действие нельзя отменить.

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();
port1.postMessage(typedArray1, [ typedArray1.buffer ]);

// The following line prints the contents of typedArray1 -- it still owns
// its memory and has been cloned, not transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2); copy

В браузерах нет эквивалента этому API.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Добавлен в: v11.13.0
  • port <MessagePort> Порт сообщения, который нужно передать.

  • contextifiedSandbox <Object> Объект, контекстефицированный, возвращаемый методом vm.createContext().

  • Возвращает: <MessagePort>

Передача MessagePort в другой vm Контекст. Исходный объект port становится непригодным для использования, и возвращённый экземпляр MessagePort занимает его место.

Возвращённый MessagePort — это объект в целевом контексте и наследует от глобального класса Object. Объекты, переданные в обработчик port.onmessage(), также создаются в целевом контексте и наследуют от его глобального класса Object.

Однако созданный MessagePort больше не наследует от EventTarget, и только port.onmessage() может быть использовано для получения событий с его помощью.

worker.parentPort

Добавлен в: v10.5.0
  • <null> | <MessagePort>

Если этот поток является потоком Worker, это MessagePort, позволяющий общаться с родительским потоком. Сообщения, отправленные с помощью parentPort.postMessage() доступны в родительском потоке с помощью worker.on('message'), а сообщения, отправленные из родительского потока с помощью worker.postMessage() доступны в этом потоке с помощью parentPort.on('message').

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

if (isMainThread) {
  const worker = new Worker(__filename);
  worker.once('message', (message) => {
    console.log(message);  // Prints 'Hello, world!'.
  });
  worker.postMessage('Hello, world!');
} else {
  // When a message from the parent thread is received, send it back:
  parentPort.once('message', (message) => {
    parentPort.postMessage(message);
  });
} copy

worker.receiveMessageOnPort(port)

История
Версия Изменения
v15.12.0

Аргумент порт теперь также может ссылаться на BroadcastChannel.

v12.3.0

Добавлен в: v12.3.0

  • port <MessagePort> | <BroadcastChannel>

  • Возвращает: <Object> | <undefined>

Получение единственного сообщения от заданного MessagePort. Если сообщение недоступно, возвращается undefined, в противном случае — объект с единственным свойством message, содержащим полезную нагрузку сообщения, соответствующую самому старому сообщению в очереди MessagePort.

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

console.log(receiveMessageOnPort(port2));
// Prints: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// Prints: undefined copy

При использовании этой функции не генерируется событие 'message' и не вызывается обработчик onmessage.

worker.resourceLimits

Добавлен в: v13.2.0, v12.16.0
  • <Object>
    • maxYoungGenerationSizeMb <число>
    • maxOldGenerationSizeMb <число>
    • codeRangeSizeMb <число>
    • stackSizeMb <число>

Предоставляет набор ограничений ресурсов движка JS внутри потока рабочего. Если параметр resourceLimits был передан в конструктор Worker, это соответствует его значениям.

Если это используется в основном потоке, его значением является пустой объект.

worker.SHARE_ENV

Добавлен в: v11.14.0
  • <символ>

Специальное значение, которое может быть передано в качестве параметра env конструктора Worker, чтобы указать, что текущий поток и поток рабочего должны совместно использовать доступ для чтения и записи к одному набору переменных окружения.

const { Worker, SHARE_ENV } = require('node:worker_threads');
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
  .on('exit', () => {
    console.log(process.env.SET_IN_WORKER);  // Prints 'foo'.
  }); copy

worker.setEnvironmentData(key[, value])

История
Версия Изменения
v17.5.0, v16.15.0

Больше не экспериментальный.

v15.12.0, v14.18.0

Добавлен в: v15.12.0, v14.18.0

  • key <любой> Любое произвольное, клонируемое значение JavaScript, которое может использоваться в качестве ключа <Map>.
  • value <любой> Любое произвольное, клонируемое значение JavaScript, которое будет клонировано и автоматически передано всем новым экземплярам Worker. Если value передаётся в качестве undefined, любое ранее установленное значение для key будет удалено.

API worker.setEnvironmentData() устанавливает содержимое worker.getEnvironmentData() в текущем потоке и во всех новых экземплярах Worker , порождённых из текущего контекста.

worker.threadId

Добавлен в: v10.5.0
  • <целое>

Целое идентификатор текущего потока. В соответствующем объекте рабочего (если таковой имеется), он доступен как worker.threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.

worker.workerData

Added in: v10.5.0

Произвольное значение JavaScript, содержащее клон данных, переданных в конструктор этого потока Worker.

Данные клонируются так же, как если бы использовалась функция postMessage() согласно алгоритму структурированного клонирования HTML.

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

Класс: BroadcastChannel extends EventTarget

История
Версия Изменения
v18.0.0

Больше не экспериментальная.

v15.4.0

Добавлена в: v15.4.0

Экземпляры класса BroadcastChannel позволяют осуществлять асинхронную двустороннюю коммуникацию между всеми экземплярами BroadcastChannel , привязанными к одному имени канала.

'use strict';

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

const bc = new BroadcastChannel('hello');

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

new BroadcastChannel(name)

Added in: v15.4.0
  • name <любое> Имя канала для подключения. Разрешается любое значение JavaScript, которое может быть преобразовано в строку с помощью `${name}`.

broadcastChannel.close()

Added in: v15.4.0

Закрывает соединение BroadcastChannel.

broadcastChannel.onmessage

Added in: v15.4.0
  • Тип: <Функция> Вызывается с одним аргументом — MessageEvent, при получении сообщения.

broadcastChannel.onmessageerror

Added in: v15.4.0
  • Тип: <Функция> Вызывается, если полученное сообщение невозможно десериализовать.

broadcastChannel.postMessage(message)

Added in: v15.4.0
  • message <любое> Любое клонируемое значение JavaScript.

broadcastChannel.ref()

Added in: v15.4.0

Противный метод unref(). Вызов ref() на ранее unref() канале BroadcastChannel не завершает программу, если это единственная активная ссылка. Если порт ref(), повторный вызов ref() не повлияет.

broadcastChannel.unref()

Added in: v15.4.0

Вызов unref() для BroadcastChannel позволяет потоку завершиться, если это единственная активная ссылка в системе событий. Если BroadcastChannel уже unref()ed, повторный вызов unref() не повлияет.

Класс: MessageChannel

Added in: v10.5.0

Экземпляры класса worker.MessageChannel представляют собой асинхронный двусторонний канал связи. У класса MessageChannel нет собственных методов. new MessageChannel() возвращает объект со свойствами port1 и port2, которые ссылаются на связанные экземпляры MessagePort.

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 copy

Класс: MessagePort

История
Версия Изменения
v14.7.0

Теперь этот класс наследуется от EventTarget вместо EventEmitter.

v10.5.0

Добавлен в: v10.5.0

  • Расширяет: <EventTarget>

Экземпляры класса worker.MessagePort представляют собой один конец асинхронного двустороннего канала связи. Он может использоваться для передачи структурированных данных, областей памяти и других MessagePort между разными Worker.

Эта реализация соответствует браузерным MessagePort.

Событие: 'close'

Добавлен в: v10.5.0

Событие 'close' генерируется, когда одна из сторон канала отключилась.

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

// Prints:
//   foobar
//   closed!
port2.on('message', (message) => console.log(message));
port2.on('close', () => console.log('closed!'));

port1.postMessage('foobar');
port1.close(); copy

Событие: 'message'

Добавлен в: v10.5.0
  • value <any> Переданное значение

Событие 'message' генерируется при поступлении сообщения, содержащего клонированный входящий параметр из port.postMessage().

Обработчики этого события получают клон параметра value, переданного в postMessage(), и больше никаких аргументов.

Событие: 'messageerror'

Добавлен в: v14.5.0, v12.19.0
  • error <Error> Объект Error

Событие 'messageerror' генерируется, когда произошла ошибка при десериализации сообщения.

В настоящее время это событие генерируется, когда на стороне получения произошла ошибка при создании опубликованного объекта JS. Такие ситуации редки, но могут произойти, например, когда некоторые объекты API Node.js получают в vm.Context (где API Node.js в настоящее время недоступны).

port.close()

Добавлен в: v10.5.0

Отключает дальнейшую отправку сообщений с любой стороны соединения. Этот метод можно вызвать, когда дальнейшее общение по этому MessagePort не потребуется.

Событие 'close' генерируется на обоих экземплярах MessagePort канала.

port.postMessage(value[, transferList])

История
Версия Изменения
v15.6.0

Добавлен X509Certificate в список клонируемых типов.

v15.0.0

Добавлен CryptoKey в список клонируемых типов.

v15.14.0, v14.18.0

Добавлен 'BlockList' в список клонируемых типов.

v15.9.0, v14.18.0

Добавлены типы 'Histogram' в список клонируемых типов.

v14.5.0, v12.19.0

Добавлен KeyObject в список клонируемых типов.

v14.5.0, v12.19.0

Добавлен FileHandle в список передаваемых типов.

v10.5.0

Добавлен в: v10.5.0

  • value <any>
  • transferList <Object[]>

Отправляет значение JavaScript на принимающую сторону канала. value передаётся способом, совместимым с алгоритмом структурированного клонирования HTML.

Основные отличия от JSON:

  • value может содержать циклические ссылки.
  • value может содержать экземпляры встроенных типов JavaScript, таких как RegExpы, BigIntы, Mapы, Setы и т.д.
  • value может содержать типизированные массивы, как с использованием ArrayBufferов, так и SharedArrayBufferов.
  • value может содержать экземпляры WebAssembly.Module.
  • value может не содержать собственных (поддерживаемых C++) объектов, кроме:
    • <CryptoKey>ов,
    • <FileHandle>ов,
    • <Histogram>ов,
    • <KeyObject>ов,
    • <MessagePort>ов,
    • <net.BlockList>ов,
    • <net.SocketAddress>ов,
    • <X509Certificate>ов.
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); copy

transferList может быть списком ArrayBuffer, MessagePort и FileHandle объектов. После передачи они больше не доступны на стороне отправки (даже если они не содержатся в value). В отличие от процессов-потомков, передача дескрипторов, таких как сокеты сети, в настоящее время не поддерживается.

Если value содержит экземпляры SharedArrayBuffer, они доступны с любой стороны. Их нельзя перечислять в transferList.

value может по-прежнему содержать ArrayBuffer экземпляры, которые не входят в transferList; в этом случае основная память копируется, а не перемещается.

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 ]); copy

Объект сообщения клонируется немедленно и может быть изменён после отправки без побочных эффектов.

Дополнительную информацию о механизмах сериализации и десериализации, стоящих за этим API, см. в API сериализации модуля node:v8.

Учитывайте при передаче TypedArrays и буферов

Все экземпляры TypedArray и Buffer являются представлениями базовой ArrayBuffer. То есть именно ArrayBuffer фактически хранит исходные данные, в то время как TypedArray и Buffer объекты предоставляют способ просмотра и изменения данных. Возможна и распространена ситуация, когда несколько представлений создаются на основе одного экземпляра ArrayBuffer. Следует проявлять особую осторожность при использовании списка передачи для передачи ArrayBuffer, так как это делает все TypedArray и Buffer экземпляры, использующие тот же ArrayBuffer, непригодными для использования.

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 copy

Для экземпляров Buffer, в частности, вопрос о том, может ли быть передан или клонирован базовый ArrayBuffer, зависит полностью от способа создания экземпляров, что часто не позволяет надёжно определить.

Экземпляр ArrayBuffer можно пометить с помощью markAsUntransferable(), чтобы указать, что его всегда следует клонировать, а не передавать.

В зависимости от способа создания экземпляра Buffer, он может или не может владеть своим базовым ArrayBuffer. Экземпляр ArrayBuffer нельзя передавать, если не известно, что экземпляр Buffer владеет им. В частности, для Bufferов, созданных из внутреннего пула Buffer (например, с использованием Buffer.from() или Buffer.allocUnsafe() ), передача невозможна и они всегда клонируются, что отправляет копию всего пула Buffer.

См. Buffer.allocUnsafe() для получения дополнительной информации о пуле Buffer.

ArrayBuffer экземпляров Buffer созданных с помощью Buffer.alloc() или Buffer.allocUnsafeSlow(), всегда можно передавать, но при этом все другие существующие представления этих 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 } copy

Это ограничение распространяется на многие встроенные объекты, такие как глобальный объект URL:

const { port1, port2 } = new MessageChannel();

port1.onmessage = ({ data }) => console.log(data);

port2.postMessage(new URL('https://example.org'));

// Prints: { } copy

port.hasRef()

Добавлен в: v18.1.0, v16.17.0
Устойчивость: 1 - Экспериментальная
  • Возвращает: <boolean>

Если true, объект MessagePort сохранит активным цикл событий Node.js.

port.ref()

Добавлен в: v10.5.0

Противоположность unref(). Вызов ref() для ранее unref() порта не завершит программу, если это единственная активная обработка (по умолчанию). Если порт ref() , повторный вызов ref() не имеет эффекта.

Если обработчики прикрепляются или удаляются с помощью .on('message'), порт ref() и unref() автоматически в зависимости от того, существуют ли обработчики события.

port.start()

Добавлен в: v10.5.0

Начинает приём сообщений на этом MessagePort. При использовании порта в качестве генератора событий, это происходит автоматически после добавления обработчиков 'message'.

Этот метод существует для соответствия API веб-потоков. В Node.js он полезен только для игнорирования сообщений, когда нет обработчиков событий. Node.js также отличается в обработке .onmessage. Установка автоматически вызывает .start(), а отключение позволяет сообщениям накапливаться до тех пор, пока не будет установлен новый обработчик или порт не будет удалён.

port.unref()

Добавлен в: v10.5.0

Вызов unref() для порта позволяет потоку завершиться, если это единственная активная обработка в системе событий. Если порт уже unref()н, вызов unref() снова не повлияет.

Если слушатели добавляются или удаляются с помощью .on('message'), порт ref()тся и unref()тся автоматически в зависимости от того, существуют ли слушатели для события.

Класс: Worker

Добавлен в: v10.5.0
  • Расширяет: <EventEmitter>

Класс Worker представляет собой независимую нить выполнения JavaScript. Внутри него доступны большинство API Node.js.

Существенные отличия в среде Worker:

  • Потоки process.stdin, process.stdout и process.stderr могут быть перенаправлены родительской нитью.
  • Свойство require('node:worker_threads').isMainThread установлено в false.
  • Доступен порт сообщений require('node:worker_threads').parentPort.
  • process.exit() не останавливает всю программу, а только текущую нить, и process.abort() недоступен.
  • Методы process.chdir() и process установки идентификаторов группы или пользователя недоступны.
  • process.env — это копия переменных среды родительской нити, если не указано иное. Изменения в одной копии не видны в других нитях и не видны нативным плагинам (если worker.SHARE_ENV не передан в качестве параметра env конструктору Worker). В Windows, в отличие от основной нити, копия переменных среды работает в регистрозависимом режиме.
  • process.title не может быть изменён.
  • Сигналы не передаются через process.on('...').
  • Выполнение может остановиться в любой момент в результате вызова worker.terminate().
  • Каналы IPC от родительских процессов недоступны.
  • Модуль trace_events не поддерживается.
  • Нативные плагины могут загружаться только из нескольких потоков, если они удовлетворяют определённым условиям.

Создание экземпляров Worker внутри других Worker возможно.

Подобно веб-потокам и модулю node:cluster, двустороннее общение может быть реализовано посредством межпотокового обмена сообщениями. Внутренне, Worker имеет встроенную пару MessagePort, которые уже связаны друг с другом при создании Worker. Хотя объект MessagePort со стороны родительского потока не доступен напрямую, его функциональность доступна через worker.postMessage() и событие worker.on('message') на объекте Worker родительского потока.

Для создания пользовательских каналов связи (что рекомендуется вместо использования глобального канала, так как это способствует разделению задач), пользователи могут создать объект MessageChannel в любом потоке и передать один из MessagePort в этом MessageChannel в другой поток через существующий канал, например, глобальный.

Для получения более подробной информации о передаче сообщений и типах значений JavaScript, которые могут быть успешно перенесены через потоковую границу, см. port.postMessage().

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

new Worker(filename[, options])

История
Версия Изменения
v19.8.0

Добавлена поддержка параметра name, который позволяет добавить имя в заголовок worker для отладки.

v14.9.0

Параметр filename может быть объектом WHATWG URL с использованием протокола data:.

v14.9.0

Параметр trackUnmanagedFds был установлен по умолчанию в true.

v14.6.0, v12.19.0

Введён параметр trackUnmanagedFds.

v13.13.0, v12.17.0

Введён параметр transferList.

v13.12.0, v12.17.0

Параметр filename может быть объектом WHATWG URL с использованием протокола file:.

v13.4.0, v12.16.0

Введён параметр argv.

v13.2.0, v12.16.0

Введён параметр resourceLimits.

v10.5.0

Добавлен в: v10.5.0

  • filename <string> | <URL> Путь к главному скрипту или модулю Worker. Должен быть либо абсолютным, либо относительным путём (относительно текущей рабочей директории), начинающимся с ./ или ../, или объектом WHATWG URL , использующим протокол file: или data:. При использовании data: URL, данные интерпретируются на основе MIME-типа с помощью загрузчика модулей ECMAScript . Если options.eval равно true, это строка, содержащая JavaScript-код, а не путь.
  • options <Object>
    • argv <any[]> Список аргументов, которые будут преобразованы в строки и добавлены к process.argv в рабочем процессе. Это в основном аналогично workerData, но значения доступны в глобальном process.argv как если бы они были переданы в качестве аргументов командной строки скрипту.
    • env <Object> Если установлено, задаёт начальное значение process.env внутри потока рабочего процесса. В качестве специального значения можно использовать worker.SHARE_ENV, чтобы указать, что родительский и дочерний потоки должны совместно использовать свои переменные среды; в этом случае изменения в объекте process.env одного потока также влияют на другой поток. По умолчанию: process.env.
    • eval <boolean> Если true и первый аргумент — string, интерпретировать первый аргумент конструктора как скрипт, который выполняется после запуска рабочего процесса.
    • execArgv <string[]> Список параметров командной строки узла, переданных рабочему процессу. 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> Любое значение JavaScript, которое клонируется и становится доступным как require('node:worker_threads').workerData. Клонирование происходит в соответствии с алгоритмом структурированного клонирования HTML . Если объект не может быть клонирован (например, если он содержит functions), выбрасывается ошибка.
    • trackUnmanagedFds <boolean> Если это установлено в true, рабочий процесс отслеживает сырые дескрипторы файлов, управляемые с помощью fs.open() и fs.close(), и закрывает их при завершении рабочего процесса, подобно другим ресурсам, таким как сетевые сокеты или дескрипторы файлов, управляемые API FileHandle. Этот параметр автоматически наследуется всеми вложенными Workers. По умолчанию: true.
    • transferList <Object[]> Если один или несколько объектов типа MessagePort передаются в workerData, для этих элементов требуется transferList, иначе будет выброшено исключение ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST. Дополнительная информация доступна в port.postMessage().
    • resourceLimits <Object> Необязательный набор ограничений ресурсов для нового экземпляра JS-движка. Достижение этих ограничений приводит к завершению экземпляра Worker. Эти ограничения влияют только на JS-движок и не на внешние данные, включая ArrayBuffers. Даже если эти ограничения установлены, процесс может прерваться, если он столкнётся с глобальной ситуацией недостатка памяти.
      • maxOldGenerationSizeMb <number> Максимальный размер основного стека в МБ. Если аргумент командной строки --max-old-space-size установлен, он переопределяет это значение.
      • maxYoungGenerationSizeMb <number> Максимальный размер кучи для недавно созданных объектов. Если аргумент командной строки --max-semi-space-size установлен, он переопределяет это значение.
      • codeRangeSizeMb <number> Размер предварительно выделенного диапазона памяти, используемого для сгенерированного кода.
      • stackSizeMb <number> Максимальный размер стека по умолчанию для потока. Малые значения могут привести к непригодности экземпляров Worker. По умолчанию: 4.
    • name <string> Необязательная name строка, которая добавляется к названию рабочего процесса для целей отладки/идентификации, делая окончательное название [worker ${id}] ${name}. По умолчанию: ''.

Событие: 'error'

Добавлен в: v10.5.0
  • err <Ошибка>

Событие 'error' генерируется, если поток рабочего процесса вызывает необработанное исключение. В этом случае рабочий процесс завершается.

Событие: 'exit'

Добавлен в: v10.5.0
  • exitCode <целое число>

Событие 'exit' генерируется после остановки рабочего процесса. Если рабочий процесс завершился вызовом process.exit(), параметр exitCode — это переданный код завершения. Если рабочий процесс был прерван, параметр exitCode равен 1.

Это последнее событие, генерируемое любым экземпляром Worker.

Событие: 'message'

Добавлен в: v10.5.0
  • value <любое> Переданное значение

Событие 'message' генерируется, когда поток рабочего процесса вызвал require('node:worker_threads').parentPort.postMessage(). Подробнее см. событие port.on('message').

Все сообщения, отправленные из потока рабочего процесса, генерируются перед событием 'exit' в объекте Worker.

Событие: 'messageerror'

Добавлен в: v14.5.0, v12.19.0
  • 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 <Object>
    • exposeInternals <boolean> Если true, отображать внутренние данные в снимке кучи. По умолчанию: false.
    • exposeNumericValues <boolean> Если true, отображать числовые значения в искусственных полях. По умолчанию: false.
  • Возвращает: <Promise> Promise для потока Readable, содержащего снимок кучи V8

Возвращает поток для чтения, содержащий снимок кучи V8 текущего состояния рабочего процесса. Подробнее см. v8.getHeapSnapshot().

Если поток рабочего процесса больше не работает (что может произойти до генерации события 'exit'), возвращаемое Promise отклоняется немедленно с ошибкой ERR_WORKER_NOT_RUNNING.

worker.performance

Added in: v15.1.0, v14.17.0, v12.22.0

Объект, который можно использовать для запроса информации о производительности экземпляра рабочего процесса. Аналогично perf_hooks.performance.

performance.eventLoopUtilization([utilization1[, utilization2]])
Added in: v15.1.0, v14.17.0, v12.22.0
  • utilization1 <Объект> Результат предыдущего вызова eventLoopUtilization().
  • utilization2 <Объект> Результат предыдущего вызова eventLoopUtilization() до utilization1.
  • Возвращает: <Объект>
    • idle <число>
    • active <число>
    • utilization <число>

Такой же вызов, как perf_hooks eventLoopUtilization(), но возвращает значения экземпляра рабочего процесса.

Разница заключается в том, что, в отличие от основного потока, запуск в рабочем процессе выполняется в цикле событий. Поэтому использование цикла событий сразу доступно после начала выполнения скрипта рабочего процесса.

Время idle, которое не увеличивается, не означает, что рабочий процесс застрял в процессе запуска. Следующий пример показывает, как всё время жизни рабочего процесса не накапливается ни одного idle времени, но он по-прежнему может обрабатывать сообщения.

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

if (isMainThread) {
  const worker = new Worker(__filename);
  setInterval(() => {
    worker.postMessage('hi');
    console.log(worker.performance.eventLoopUtilization());
  }, 100).unref();
  return;
}

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

Использование цикла событий рабочего процесса доступно только после того, как испущен 'online' событие, и если оно вызвано до этого или после 'exit' события, все свойства имеют значение 0.

worker.postMessage(value[, transferList])

Added in: v10.5.0
  • value <любой>
  • transferList <Массив объектов>

Отправить сообщение рабочему процессу, которое будет получено через require('node:worker_threads').parentPort.on('message'). Подробнее см. port.postMessage().

worker.ref()

Added in: v10.5.0

Противоположность unref(), вызов ref() для ранее unref() рабочего процесса не позволяет программе завершиться, если это единственная активная обработка (по умолчанию). Если рабочий процесс ref()ed, повторный вызов ref() не оказывает никакого влияния.

worker.resourceLimits

Added in: v13.2.0, v12.16.0
  • <Объект>
    • maxYoungGenerationSizeMb <число>
    • maxOldGenerationSizeMb <число>
    • codeRangeSizeMb <число>
    • stackSizeMb <число>

Предоставляет набор ограничений ресурсов JS-движка для этого потока рабочего процесса. Если параметр resourceLimits был передан конструктору Worker, то он соответствует его значениям.

Если рабочий процесс остановлен, возвращаемое значение — пустой объект.

worker.stderr

Added in: v10.5.0
  • <stream.Readable>

Это потоковый объект для чтения данных, записанных в process.stderr внутри потока рабочего процесса. Если параметр stderr: true не был передан конструктору Worker, данные передаются потоку process.stderr родительского потока.

worker.stdin

Added in: v10.5.0
  • <null> | <stream.Writable>

Если параметр stdin: true был передан конструктору Worker, это потоковый объект для записи. Данные, записанные в этот поток, будут доступны в потоке рабочего процесса как process.stdin.

worker.stdout

Added in: v10.5.0
  • <stream.Readable>

Это потоковый объект для чтения данных, записанных в process.stdout внутри потока рабочего процесса. Если параметр stdout: true не был передан конструктору Worker, данные передаются потоку process.stdout родительского потока.

worker.terminate()

История
Версия Изменения
v12.5.0

Эта функция теперь возвращает Promise. Передача обратного вызова устарела и была бесполезна до этой версии, так как рабочий процесс фактически завершался синхронно. Теперь завершение — полностью асинхронная операция.

v10.5.0

Добавлен: v10.5.0

  • Возвращает: <Promise>

Остановить выполнение JavaScript в потоке рабочего процесса как можно скорее. Возвращает Promise кода выхода, который выполняется при запуске 'exit' события.

worker.threadId

Added in: v10.5.0
  • <целое число>

Целое число — идентификатор для связанного потока. Внутри потока рабочего процесса он доступен как require('node:worker_threads').threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.

worker.unref()

Added in: v10.5.0

Вызов unref() для рабочего процесса позволяет потоку завершиться, если это единственная активная обработка в системе событий. Если рабочий процесс уже unref()ed, повторный вызов unref() не оказывает никакого влияния.

Примечания

Синхронная блокировка stdio

Worker используют передачу сообщений через <MessagePort> для взаимодействия с stdio. Это означает, что вывод stdio, исходящий от Worker, может быть заблокирован синхронным кодом на стороне получателя, который блокирует цикл событий Node.js.

Модули MJS

import {
  Worker,
  isMainThread,
} from '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');
}

Модули CJS

'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');
}

Запуск потоков рабочего процесса из скриптов preload

Будьте внимательны при запуске потоков рабочего процесса из скриптов preload (скрипты загружаются и выполняются с помощью флага командной строки -r). Если параметр execArgv не установлен явно, новые потоки рабочего процесса автоматически наследуют флаги командной строки от выполняемого процесса и предварительно загрузят те же скрипты preload, что и основной поток. Если скрипт preload безусловно запускает поток рабочего процесса, каждый созданный поток будет запускать ещё один, пока приложение не рухнет.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v20.x/docs/api/worker_threads.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API