Spec-Zone.ru › Node.js 16 LTS

Потоки обработки

Устойчивость: 2 - Стабильно

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

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

const worker = require('worker_threads');

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

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

const {
  Worker, isMainThread, parentPort, workerData
} = require('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));
}

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

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

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

worker.getEnvironmentData(key)

Добавлен в: v15.12.0
Устойчивость: 1 - Экспериментальный
  • key <любое> Любое произвольное клонируемое значение JavaScript, которое можно использовать в качестве ключа <Map>.
  • Возвращает: <любое>

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

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

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

worker.isMainThread

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

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

const { Worker, isMainThread } = require('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'.
}

worker.markAsUntransferable(object)

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

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

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

Эта операция не может быть отменена.

const { MessageChannel, markAsUntransferable } = require('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);

В браузерах нет эквивалента этому 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('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);
  });
}

worker.receiveMessageOnPort(port)

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

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

v12.3.0

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

  • port <MessagePort> | <BroadcastChannel>

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

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

const { MessageChannel, receiveMessageOnPort } = require('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

При использовании этой функции событие '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('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'.
  });

worker.setEnvironmentData(key[, value])

Добавлен в: v15.12.0
Устойчивость: 1 - Экспериментальный
  • 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('worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hello, world!' });
} else {
  console.log(workerData);  // Prints 'Hello, world!'.
}

Класс: BroadcastChannel extends EventTarget

Added in: v15.4.0
Уровень стабильности: 1 - Экспериментальный

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

'use strict';

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

const bc = new BroadcastChannel('hello');

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

new BroadcastChannel(name)

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() , повторный вызов unref() не окажет никакого действия.

Класс: MessageChannel

Added in: v10.5.0

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

const { MessageChannel } = require('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

Класс: 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('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();

Событие: '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.14.0

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

v15.9.0

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

v15.6.0

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

v15.0.0

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

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 может содержать экземпляры встроенных типов JS, таких как RegExps, BigInts, Maps, Sets и т.д.
  • value может содержать типизированные массивы, используя ArrayBuffers и SharedArrayBuffers.
  • value может содержать экземпляры WebAssembly.Module.
  • value не может содержать нативные (поддерживаемые C++) объекты, кроме:
    • <CryptoKey>s,
    • <FileHandle>s,
    • <Histogram>s,
    • <KeyObject>s,
    • <MessagePort>s,
    • <net.BlockList>s,
    • <net.SocketAddress>es,
    • <X509Certificate>s.
const { MessageChannel } = require('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);

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

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

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

const { MessageChannel } = require('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 ]);

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

Для получения дополнительной информации о механизмах сериализации и десериализации этого API, см. API сериализации модуля 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

Для экземпляров 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 }

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

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

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

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

// Prints: { }

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()ed, повторный вызов unref() не повлияет.

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

Класс: Worker

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

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

Примечательные различия в среде Worker:

  • Перенаправление process.stdin, process.stdout и process.stderr может быть выполнено родительской нитью.
  • Свойство require('worker_threads').isMainThread установлено в false.
  • Доступен порт сообщений require('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 возможно.

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

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

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

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

new Worker(filename[, options])

История
Версия Изменения
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 <массив строк> Список параметров командной строки для узла, переданных рабочему потоку. 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('worker_threads').workerData. Клонирование происходит согласно алгоритму структурированного клонирования HTML, и если объект нельзя клонировать (например, потому что он содержит function), выбрасывается ошибка.
    • trackUnmanagedFds <булево> Если это установлено в true, то Рабочий поток отслеживает необработанные дескрипторы файлов, управляемые с помощью fs.open() и fs.close(), и закрывает их при выходе Рабочего потока, аналогично другим ресурсам, таким как сетевые сокеты или дескрипторы файлов, управляемые через FileHandle API. Этот параметр автоматически наследуется всеми вложенными Worker. По умолчанию: true.
    • transferList <массив объектов> Если один или несколько MessagePort-подобных объектов передаются в workerData, для этих элементов требуется transferList, иначе выбрасывается ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST. См. port.postMessage() для получения дополнительной информации.
    • resourceLimits <Объект> Необязательный набор ограничений ресурсов для новой экземпляра JS движка. Достижение этих ограничений приводит к завершению экземпляра Worker . Эти ограничения влияют только на JS движок, а не на внешние данные, включая ArrayBuffer. Даже если эти ограничения заданы, процесс может всё равно прерваться, если столкнётся с глобальной ситуацией недостатка памяти.
      • maxOldGenerationSizeMb <число> Максимальный размер основного куска памяти в МБ.
      • maxYoungGenerationSizeMb <число> Максимальный размер куска памяти для недавно созданных объектов.
      • codeRangeSizeMb <число> Размер предварительно выделенного диапазона памяти, используемого для сгенерированного кода.
      • stackSizeMb <число> Максимальный размер стека потока по умолчанию. Маленькие значения могут привести к непригодности экземпляров Рабочих потоков. По умолчанию: 4.

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

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

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

worker.performance

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

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

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

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

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

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

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

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

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

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

worker.postMessage(value[, transferList])

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

Отправка сообщения рабочему процессу, которое принимается через require('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 <число>

Предоставляет набор ограничений ресурсов движка JavaScript для данного потока рабочего процесса. Если опция 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('worker_threads').threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.

worker.unref()

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

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

Примечания

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

Рабочие процессы используют обмен сообщениями через <MessagePort> для взаимодействия с stdio. Это означает, что вывод stdio , исходящий от рабочего процесса, может быть заблокирован синхронным кодом на стороне получателя, который блокирует цикл событий 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++) {}
} else {
  // This output will be blocked by the for loop in the main thread.
  console.log('foo');
}

Модули CJS

'use strict';

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

if (isMainThread) {
  new Worker(__filename);
  for (let n = 0; n < 1e10; n++) {}
} 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-v16.x/docs/api/worker_threads.html

Spec-Zone.ru

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