Spec-Zone.ru › Node.js 18 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

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

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

Аргумент port теперь также может ссылаться на 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

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

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 , запущенных из текущего контекста.

END_OF_DOCUMENT_MARKER

worker.threadId

Added in: 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()ed, повторный вызов 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 <любой> Передаваемое значение

Событие '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])

История
Версия Изменения
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
Стабильность: 1 - Экспериментально
  • Возвращает: <булево>

Если true, объект MessagePort будет поддерживать активность цикла событий Node.js.

port.ref()

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

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

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

port.start()

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

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

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

port.unref()

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

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

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

Класс: Worker

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

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

Отличия в среде Рабочего потока:

  • Потоки 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).
  • 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])

История
Версия Изменения
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 data:. Если 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 <массив строк> Список параметров командной строки узла, переданных рабочему потоку. Параметры 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 require('node:worker_threads').workerData, и ошибка генерируется, если объект не может быть склонирован (например, потому что он содержит 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 <число> Максимальный размер стека потока по умолчанию. Маленькие значения могут привести к непригодности инстанций Рабочего потока. По умолчанию: 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 <Ошибка> Объект Error

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

Событие: 'online'

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

Событие 'online' генерируется, когда поток Рабочего потока начал выполнение кода JavaScript.

worker.getHeapSnapshot()

Добавлен в: v13.9.0, v12.17.0
  • Возвращает: <Promise> Обещание потока чтения, содержащего снимок кучи V8

Возвращает поток чтения для снимка кучи V8 текущего состояния Рабочего потока. Дополнительную информацию см. в разделе v8.getHeapSnapshot().

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

worker.performance

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

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

performance.eventLoopUtilization([utilization1[, utilization2]])
Добавлен в: v15.1.0, v14.17.0, v12.22.0
  • utilization1 <Объект> Результат предыдущего вызова 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])

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

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

worker.ref()

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

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

worker.resourceLimits

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

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

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

worker.stderr

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

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

worker.stdin

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

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

worker.stdout

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

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

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

worker.unref()

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

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

Примечания

Синхронная блокировка ввода-вывода

Рабочие потоки используют передачу сообщений через <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');
}

Запуск рабочих потоков из скриптов предварительной загрузки

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

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

Spec-Zone.ru

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