Потоки обработки задач
Исходный код: 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)
-
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
Истинно, если этот код не выполняется внутри потока 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)
-
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)
-
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)
-
port<MessagePort> Порт сообщений для передачи. -
contextifiedSandbox<Объект> Объект, преобразованный в контекст, как возвращается методомvm.createContext(). -
Возвращает: <MessagePort>
Передача MessagePort в другой vm контекст. Исходный объект port становится непригодным, а возвращенный MessagePort экземпляр занимает его место.
Возвращённый MessagePort — это объект в целевом контексте, унаследованный от его глобального класса Object. Объекты, переданные в обработчик port.onmessage(), также создаются в целевом контексте и наследуют глобальный класс Object.
Однако созданный MessagePort больше не наследует от EventTarget, и только port.onmessage() можно использовать для получения событий с его помощью.
worker.parentPort
Если этот поток — 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)
-
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
Предоставляет набор ограничений ресурсов движка JS внутри потока обработки задач. Если параметр resourceLimits был передан конструктору Worker, это соответствует его значениям.
Если это используется в главном потоке, его значение — пустой объект.
worker.SHARE_ENV
Особое значение, которое можно передать как параметр 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])
-
key<любое> Любое произвольное, клонируемое значение JavaScript, которое может использоваться в качестве ключа для <Map>. -
value<любое> Любое произвольное, клонируемое значение JavaScript, которое будет клонировано и автоматически передано всем новымWorkerэкземплярам. Еслиvalueпередается какundefined, любое ранее заданное значение дляkeyбудет удалено.
API worker.setEnvironmentData() устанавливает содержимое worker.getEnvironmentData() в текущем потоке и во всех новых экземплярах Worker , созданных из текущего контекста.
worker.threadId
Целочисленный идентификатор текущего потока. В соответствующем объекте worker (если он есть), он доступен как worker.threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.
worker.workerData
Произвольное значение 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
Экземпляры 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)
-
name<любое> Имя канала для подключения. Разрешено любое значение JavaScript, которое может быть преобразовано в строку с помощью`${name}`.
broadcastChannel.close()
Закрывает соединение BroadcastChannel.
broadcastChannel.onmessage
- Тип: <Функция> Вызывается с одним аргументом
MessageEventпри получении сообщения.
broadcastChannel.onmessageerror
- Тип: <Функция> Вызывается, если полученное сообщение не может быть десериализовано.
broadcastChannel.postMessage(message)
-
message<любое> Любое клонируемое значение JavaScript.
broadcastChannel.ref()
Обратное unref(). Вызов ref() на ранее unref()ed BroadcastChannel не позволяет программе завершиться, если это единственная активная ручка (по умолчанию). Если порт ref()ed, вызов ref() не имеет эффекта.
broadcastChannel.unref()
Вызов unref() на BroadcastChannel позволяет потоку завершиться, если это единственная активная ручка в системе событий. Если BroadcastChannel уже unref()ed, вызов unref() не имеет эффекта.
Класс: MessageChannel
Экземпляры класса 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
- Расширяет: <EventTarget>
Экземпляры класса worker.MessagePort представляют собой один конец асинхронного двустороннего канала связи. Он может использоваться для передачи структурированных данных, областей памяти и других MessagePort между различными Worker.
Эта реализация соответствует браузерным MessagePort.
Событие: 'close'
Событие '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'
-
value<любой> Передаваемое значение
Событие 'message' генерируется для каждого входящего сообщения, содержащего клонированный ввод из port.postMessage().
Обработчики этого события получают клон параметра value в качестве входного значения для postMessage() и не получают дополнительных аргументов.
Событие: 'messageerror'
-
error<Ошибка> Объект Error
Событие 'messageerror' генерируется, когда десериализация сообщения завершилась с ошибкой.
В настоящее время это событие генерируется, когда возникает ошибка при создании опубликованного объекта JS на стороне получателя. Такие ситуации редки, но могут произойти, например, при получении некоторых объектов API Node.js в vm.Context (где API Node.js в данный момент недоступны).
port.close()
Отключает дальнейшую отправку сообщений с обеих сторон соединения. Этот метод можно вызвать, когда дальнейшая коммуникация по этому MessagePort больше не потребуется.
Событие 'close' событие генерируется на обоих экземплярах MessagePort которые являются частью канала.
port.postMessage(value[, transferList])
-
value<любой> -
transferList<Массив объектов>
Отправляет значение JavaScript на сторону получателя этого канала. value передаётся способом, совместимым с алгоритмом структурированного клонирования HTML.
В частности, существенные отличия от JSON:
-
valueможет содержать циклические ссылки. -
valueможет содержать экземпляры встроенных типов JS, такие какRegExpы,BigIntы,Mapы,Setы и т. д. -
valueможет содержать типизированные массивы, использующиеArrayBufferы иSharedArrayBufferы. -
valueможет содержать экземплярыWebAssembly.Module. -
valueне может содержать нативные (поддерживаемые C++) объекты, кроме:
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()
- Возвращает: <логическое значение>
Если истинно, объект MessagePort будет поддерживать активность цикла событий Node.js.
port.ref()
Обратное unref(). Вызов ref() на ранее unref() порту не позволяет программе завершиться, если это единственная активная обработка (по умолчанию). Если порт ref()т, повторный вызов ref() не имеет эффекта.
Если слушатели присоединяются или удаляются с помощью .on('message'), порт ref()ся и unref()ся автоматически в зависимости от наличия слушателей для события.
port.start()
Начинает получать сообщения на этом MessagePort. При использовании порта в качестве эмиттера событий, это вызывается автоматически после присоединения 'message' слушателей.
Этот метод существует для соответствия API Веб MessagePort. В Node.js он полезен только для игнорирования сообщений, когда нет слушателей событий. Node.js также отличается в обработке .onmessage. Установка его автоматически вызывает .start(), но отключение позволяет сообщениям накапливаться до тех пор, пока не будет установлен новый обработчик или порт не будет удален.
port.unref()
Вызов unref() на порте позволяет потоку завершиться, если это единственная активная обработка в системе событий. Если порт уже unref()т, повторный вызов unref() не имеет эффекта.
Если слушатели присоединяются или удаляются с помощью .on('message'), порт ref()ся и unref()ся автоматически в зависимости от наличия слушателей для события.
Класс: Worker
- Расширяет: <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])
-
filename<строка> | <URL> Путь к главному скрипту или модулю Рабочего процесса. Должен быть либо абсолютным, либо относительным путем (то есть относительным к текущей рабочей директории), начинающимся с./или../, или объектом WHATWGURLс использованием протокола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(), и закрывает их при завершении Рабочего процесса, аналогично другим ресурсам, таким как сетевые сокеты или дескрипторы файлов, управляемые APIFileHandle. Этот параметр автоматически наследуется всеми вложенными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'
-
err<Ошибка>
Событие 'error' генерируется, если поток рабочего процесса вызывает необработанное исключение. В этом случае рабочий процесс завершается.
Событие: 'exit'
-
exitCode<целое число>
Событие 'exit' генерируется, когда рабочий процесс останавливается. Если рабочий процесс завершился вызовом process.exit(), параметр exitCode — это возвращаемый код завершения. Если рабочий процесс был завершён, параметр exitCode имеет значение 1.
Это последнее событие, генерируемое экземпляром Worker.
Событие: 'message'
-
value<любое значение> Переданное значение
Событие 'message' генерируется, когда поток рабочего процесса вызывает require('node:worker_threads').parentPort.postMessage(). Дополнительные сведения см. в событии port.on('message').
Все сообщения, отправленные из потока рабочего процесса, генерируются до события 'exit', генерируемого для объекта Worker.
Событие: 'messageerror'
-
error<Объект Ошибки> Объект Ошибки
Событие 'messageerror' генерируется, когда десериализация сообщения завершается неудачно.
Событие: 'online'
Событие 'online' генерируется, когда поток рабочего процесса начинает выполнять код JavaScript.
worker.getHeapSnapshot([options])
-
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
Объект, который может использоваться для запроса информации о производительности от экземпляра worker. Аналогично perf_hooks.performance.
performance.eventLoopUtilization([utilization1[, utilization2]])
-
utilization1<Объект> Результат предыдущего вызоваeventLoopUtilization(). -
utilization2<Объект> Результат предыдущего вызоваeventLoopUtilization()доutilization1. - Возвращает: <Объект>
То же самое, что и 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])
-
value<любой> -
transferList<Массив объектов>
Отправка сообщения worker, которое принимается через require('node:worker_threads').parentPort.on('message'). Смотрите port.postMessage() для получения более подробной информации.
worker.ref()
Обратное действие unref(), вызов ref() на ранее unref() worker не завершает программу, если это последний активный дескриптор (по умолчанию). Если worker ref()ed, вызов ref() повторно не оказывает никакого влияния.
worker.resourceLimits
Предоставляет набор ограничений ресурсов движка JS для данного потока Worker. Если опция resourceLimits была передана конструктору Worker, она соответствует её значениям.
Если worker остановлен, возвращаемое значение — пустой объект.
worker.stderr
Это поток Readable, содержащий данные, записанные в process.stderr внутри потока worker. Если stderr: true не передавалась конструктору Worker, данные передаются в поток process.stderr родительского потока.
worker.stdin
Если stdin: true передавалась конструктору Worker, это поток Writable. Данные, записанные в этот поток, будут доступны в потоке worker как process.stdin.
worker.stdout
Это поток Readable, содержащий данные, записанные в process.stdout внутри потока worker. Если stdout: true не передавалась конструктору Worker, данные передаются в поток process.stdout родительского потока.
worker.terminate()
- Возвращает: <Promise>
Немедленно остановить все выполнение JavaScript в потоке worker. Возвращает Promise для кода выхода, который выполняется при выпуске 'exit' события.
worker.threadId
Целое идентификатор для указанного потока. Внутри потока worker он доступен как require('node:worker_threads').threadId. Это значение уникально для каждого экземпляра Worker в одном процессе.
worker.unref()
Вызов 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