Spec-Zone.ru › Node.js

Потоки обработки задач

Уровень стабильности: 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
  • <логическое>

Истинно, если этот код не выполняется внутри потока 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 <любое> Любое произвольное значение JavaScript.

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

В частности, это имеет смысл для объектов, которые можно клонировать, а не передавать, и которые используются другими объектами со стороны отправки. Например, 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();
try {
  // This will throw an error, because pooledBuffer is not transferable.
  port1.postMessage(typedArray1, [ typedArray1.buffer ]);
} catch (error) {
  // error.name === 'DataCloneError'
}

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

В браузерах аналог этого API отсутствует.

worker.isMarkedAsUntransferable(object)

Добавлен в: v21.0.0
  • object <любое> Любое значение JavaScript.
  • Возвращает: <логическое>

Проверить, помечен ли объект как непередаваемый с помощью markAsUntransferable().

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

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

isMarkedAsUntransferable(pooledBuffer);  // Returns true. copy

В браузерах аналог этого API отсутствует.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Добавлен в: v11.13.0
  • port <MessagePort> Порт сообщений для передачи.

  • contextifiedSandbox <Объект> Объект, преобразованный в контекст, как возвращается методом 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>

  • Возвращает: <Объект> | <не определено>

Получение одного сообщения из заданного 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
  • <Объект>
    • 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 (если он есть), он доступен как worker.threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.

worker.workerData

Добавлена в: 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)

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

broadcastChannel.close()

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

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

broadcastChannel.onmessage

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

broadcastChannel.onmessageerror

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

broadcastChannel.postMessage(message)

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

broadcastChannel.ref()

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

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

broadcastChannel.unref()

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

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

Класс: MessageChannel

Добавлена в: 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 <любой> Передаваемое значение

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

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

Событие: 'messageerror'

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

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

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

port.close()

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

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

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

port.postMessage(value[, transferList])

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

Выбрасывается ошибка, когда в списке передачи находится непередаваемый объект.

v15.6.0

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

v15.0.0

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

v15.14.0, v14.18.0

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

v15.9.0, v14.18.0

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

v14.5.0, v12.19.0

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

v14.5.0, v12.19.0

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

v10.5.0

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

  • value <любой>
  • transferList <Массив объектов>

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

В частности, существенные отличия от JSON:

  • value может содержать циклические ссылки.
  • value может содержать экземпляры встроенных типов JS, такие как 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 - Экспериментальный
  • Возвращает: <логическое значение>

Если истинно, объект 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 Веб MessagePort. В 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 возможно.

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

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

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

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, v18.16.0

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

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

Событие '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> Promise для потока Readable, содержащего дамп кучи V8

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

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

worker.performance

Добавлен в: v15.1.0, v14.17.0, v12.22.0

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

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

То же самое, что и perf_hooks eventLoopUtilization(), но возвращаются значения экземпляра worker.

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

Время idle, которое не увеличивается, не означает, что worker застрял в загрузке. В следующих примерах показано, как весь жизненный цикл worker никогда не накапливает время 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

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

worker.postMessage(value[, transferList])

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

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

worker.ref()

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

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

worker.resourceLimits

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

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

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

worker.stderr

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

Это поток Readable, содержащий данные, записанные в process.stderr внутри потока worker. Если stderr: true не передавалась конструктору Worker, данные передаются в поток process.stderr родительского потока.

worker.stdin

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

Если stdin: true передавалась конструктору Worker, это поток Writable. Данные, записанные в этот поток, будут доступны в потоке worker как process.stdin.

worker.stdout

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

Это поток Readable, содержащий данные, записанные в process.stdout внутри потока worker. Если stdout: true не передавалась конструктору Worker, данные передаются в поток process.stdout родительского потока.

worker.terminate()

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

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

v10.5.0

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

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

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

worker.threadId

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

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

worker.unref()

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

Вызов unref() для worker позволяет потоку выйти, если это единственный активный дескриптор в системе событий. Если worker уже 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');
}

Запуск потоков worker из скриптов preload

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

© 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/api/worker_threads.html

Spec-Zone.ru

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