Потоки-рабочие
Исходный код: 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
Является 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)
Отметить объект как непередаваемый. Если 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)
-
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.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() канале 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()
- Возвращает: <булево>
Если true, объект MessagePort будет поддерживать активность цикла событий Node.js.
port.ref()
Обратное unref(). Вызов ref() на ранее unref() порте не позволяет программе выйти, если это единственная активная обработка (по умолчанию). Если порт ref()ed, повторный вызов ref() не повлияет.
Если слушатели добавляются или удаляются с помощью .on('message'), порт ref()ed и unref()ed автоматически в зависимости от того, существуют ли слушатели для события.
port.start()
Начинает получение сообщений на этом MessagePort. При использовании этого порта как эмиттера событий, это вызывается автоматически после добавления 'message' слушателей.
Этот метод существует для соответствия веб-MessagePort API. В Node.js он полезен только для игнорирования сообщений, когда нет слушателей событий. Node.js также отличается в обработке .onmessage. Установка его автоматически вызывает .start(), но отмена установки позволяет сообщениям накапливаться до тех пор, пока не будет установлен новый обработчик или порт не будет удален.
port.unref()
Вызов unref() на порту позволяет потоку завершиться, если это единственная активная обработка в системе событий. Если порт уже unref()ed, повторный вызов unref() не повлияет.
Если слушатели добавляются или удаляются с помощью .on('message'), порт ref()ed и unref()ed автоматически в зависимости от наличия слушателей для события.
Класс: Worker
- Расширяет: <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])
-
filename<строка> | <URL> Путь к основному скрипту или модулю Рабочего потока. Должен быть абсолютным или относительным путем (относительно текущего каталога), начинающимся с./или../, или объектом WHATWGURLс использованием протоколаfile:илиdata:. При использованииdata:URL, данные интерпретируются на основе типа MIME с использованием загрузчика модулей ECMAScriptdata:. Если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. Клонирование выполняется в соответствии с алгоритмом структурированного клонирования HTMLrequire('node:worker_threads').workerData, и ошибка генерируется, если объект не может быть склонирован (например, потому что он содержит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<число> Максимальный размер стека потока по умолчанию. Маленькие значения могут привести к непригодности инстанций Рабочего потока. По умолчанию: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<Ошибка> Объект Error
Событие 'messageerror' генерируется, когда десериализация сообщения не удалась.
Событие: 'online'
Событие 'online' генерируется, когда поток Рабочего потока начал выполнение кода JavaScript.
worker.getHeapSnapshot()
- Возвращает: <Promise> Обещание потока чтения, содержащего снимок кучи V8
Возвращает поток чтения для снимка кучи V8 текущего состояния Рабочего потока. Дополнительную информацию см. в разделе v8.getHeapSnapshot().
Если поток Рабочего потока больше не работает, что может произойти до того, как будет генерировано событие 'exit', возвращаемое Promise отбрасывается немедленно с ошибкой ERR_WORKER_NOT_RUNNING.
worker.performance
Объект, который можно использовать для запроса информации о производительности из инстанции рабочего потока. Аналогично perf_hooks.performance.
performance.eventLoopUtilization([utilization1[, utilization2]])
-
utilization1<Объект> Результат предыдущего вызоваeventLoopUtilization(). -
utilization2<Объект> Результат предыдущего вызоваeventLoopUtilization()доutilization1. - Возвращает <Объект>
То же самое, что и 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])
-
value<любой> -
transferList<Массив объектов>
Отправьте сообщение рабочему потоку, которое будет получено с помощью require('node:worker_threads').parentPort.on('message'). Подробнее см. port.postMessage().
worker.ref()
Обратное unref(), вызов ref() в ранее unref() рабочем потоке не позволяет программе завершиться, если это единственная активная ссылка (по умолчанию). Если рабочий поток ref()ed, повторный вызов ref() не имеет эффекта.
worker.resourceLimits
Предоставляет набор ограничений ресурсов движка JS для этого потока рабочего процесса. Если опция resourceLimits была передана в конструктор Worker, это соответствует её значениям.
Если рабочий поток остановлен, возвращаемое значение — пустой объект.
worker.stderr
Это потоковый объект для чтения данных, записанных в process.stderr внутри потока рабочего процесса. Если stderr: true не передавалась в конструктор Worker, то данные направляются в потоковый объект process.stderr родительского потока.
worker.stdin
Если stdin: true передавалась в конструктор Worker, это потоковый объект для записи. Данные, записанные в этот поток, будут доступны в потоке рабочего процесса как process.stdin.
worker.stdout
Это потоковый объект для чтения данных, записанных в process.stdout внутри потока рабочего процесса. Если stdout: true не передавалась в конструктор Worker, то данные направляются в потоковый объект process.stdout родительского потока.
worker.terminate()
- Возвращает: <Promise>
Немедленно остановить всю работу JavaScript в потоке рабочего процесса. Возвращает Promise для кода завершения, который выполняется, когда генерируется событие 'exit'.
worker.threadId
Целочисленный идентификатор для указанного потока. Внутри потока рабочего процесса он доступен как require('node:worker_threads').threadId. Это значение уникально для каждого экземпляра Worker в одном процессе.
worker.unref()
Вызов 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