Потоки обработки
Исходный код: 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)
-
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
Является 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)
Пометить объект как непереносимый. Если 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)
-
port<MessagePort> Порт сообщения для передачи. -
contextifiedSandbox<Object> Объект контексте, возвращенный методом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('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)
-
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
Предоставляет набор ограничений ресурсов движка JS внутри этого потока обработки. Если параметр resourceLimits был передан в конструктор Worker, это соответствует его значениям.
Если это используется в основном потоке, его значение — пустой объект.
worker.SHARE_ENV
Специальное значение, которое может быть передано в качестве параметра 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])
-
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('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename, { workerData: 'Hello, world!' });
} else {
console.log(workerData); // Prints 'Hello, world!'.
} Класс: BroadcastChannel extends EventTarget
Экземпляры 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)
-
name<любое> Имя канала для подключения. Разрешается любое значение JavaScript, которое может быть преобразовано в строку с помощью`${name}`.
broadcastChannel.close()
Закрывает соединение BroadcastChannel.
broadcastChannel.onmessage
- Тип: <Функция> Вызывается с одним аргументом
MessageEventпри получении сообщения.
broadcastChannel.onmessageerror
- Тип: <Функция> Вызывается, если полученное сообщение нельзя десериализовать.
broadcastChannel.postMessage(message)
-
message<любое> Любое клонируемое значение JavaScript.
broadcastChannel.ref()
Обратное unref(). Вызов ref() на ранее unref() канале BroadcastChannel не позволяет программе завершиться, если это единственная активная ссылка (по умолчанию). Если порт ref() , повторный вызов ref() не окажет никакого действия.
broadcastChannel.unref()
Вызов unref() на BroadcastChannel позволяет потоку выйти, если это единственная активная ссылка в системе событий. Если BroadcastChannel уже unref() , повторный вызов unref() не окажет никакого действия.
Класс: MessageChannel
Экземпляры класса 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
- Расширяет: <EventTarget>
Экземпляры класса worker.MessagePort представляют собой один конец асинхронного двустороннего канала связи. Он может использоваться для передачи структурированных данных, областей памяти и других MessagePort между различными Worker.
Эта реализация соответствует браузерным MessagePort.
Событие: 'close'
Событие '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'
-
value<any> Передаваемое значение
Событие 'message' генерируется для каждого входящего сообщения, содержащего клонированный ввод port.postMessage().
Обработчики этого события получают клон параметра value, как он был передан в postMessage(), и без дополнительных аргументов.
Событие: 'messageerror'
-
error<Error> Объект Error
Событие 'messageerror' генерируется, когда десериализация сообщения завершилась ошибкой.
В настоящее время это событие генерируется, когда при создании объекта JS в результате отправки сообщения на стороне получателя возникает ошибка. Такие ситуации редки, но могут произойти, например, при получении определённых объектов API Node.js в vm.Context (где API Node.js в данный момент недоступны).
port.close()
Отключает дальнейшую отправку сообщений с обеих сторон соединения. Этот метод можно вызвать, когда дальнейшее общение по этому MessagePort не требуется.
Событие 'close' генерируется на обоих экземплярах MessagePort , участвующих в канале.
port.postMessage(value[, transferList])
-
value<any> -
transferList<Object[]>
Отправляет значение JavaScript на принимающую сторону канала. value передаётся так, чтобы быть совместимым с алгоритмом структурированного клонирования HTML.
В частности, существенные отличия от JSON:
-
valueможет содержать циклические ссылки. -
valueможет содержать экземпляры встроенных типов JS, таких какRegExps,BigInts,Maps,Sets и т.д. -
valueможет содержать типизированные массивы, используяArrayBuffers иSharedArrayBuffers. -
valueможет содержать экземплярыWebAssembly.Module. -
valueне может содержать нативные (поддерживаемые C++) объекты, кроме:
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()
Обратное unref(). Вызов ref() на ранее unref() порте не приводит к завершению программы, если это единственная активная ссылка (по умолчанию). Если порт ref() , вызов ref() не имеет эффекта.
Если обработчики прикреплены или удалены с помощью .on('message'), порт ref() и unref() автоматически в зависимости от того, существуют ли обработчики события.
port.start()
Начинает приём сообщений на этом MessagePort. При использовании этого порта в качестве генератора событий, это вызывается автоматически, когда 'message' обработчики прикреплены.
Этот метод существует для соответствия 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.
Примечательные различия в среде 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])
-
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<массив строк> Список параметров командной строки для узла, переданных рабочему потоку. 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(), и закрывает их при выходе Рабочего потока, аналогично другим ресурсам, таким как сетевые сокеты или дескрипторы файлов, управляемые черезFileHandleAPI. Этот параметр автоматически наследуется всеми вложенными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'
-
err<Ошибка>
Событие 'error' генерируется, если поток рабочего потока выбрасывает неперехваченное исключение. В этом случае рабочий поток завершается.
Событие: 'exit'
-
exitCode<целое число>
Событие 'exit' генерируется, когда рабочий поток останавливается. Если рабочий поток завершился вызовом process.exit(), параметр exitCode — это возвращённый код выхода. Если рабочий поток был завершён, параметр exitCode равен 1.
Это последнее событие, генерируемое любым экземпляром Worker.
Событие: 'message'
-
value<любое значение> Переданное значение
Событие 'message' генерируется, когда поток рабочего потока вызвал require('worker_threads').parentPort.postMessage(). См. событие port.on('message') для получения более подробной информации.
Все сообщения, отправленные из потока рабочего потока, генерируются до генерации события 'exit' в объекте Worker.
Событие: 'messageerror'
-
error<Ошибка> Объект Error
Событие 'messageerror' генерируется, когда десериализация сообщения завершилась неудачно.
Событие: 'online'
Событие 'online' генерируется, когда поток рабочего потока начал выполнять JavaScript-код.
worker.getHeapSnapshot()
- Возвращает: <Promise> Promise для потокового объекта Readable, содержащего снимок куска памяти V8
Возвращает потоковый объект Readable для снимка куска памяти 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('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])
-
value<любой тип> -
transferList<Массив объектов>
Отправка сообщения рабочему процессу, которое принимается через require('worker_threads').parentPort.on('message'). Дополнительные сведения см. в разделе port.postMessage().
worker.ref()
Обратное действие unref(), вызов ref() для ранее unref() рабочего процесса не приводит к завершению программы, если это единственная активная ссылка (по умолчанию). Если рабочий процесс ref()ed, повторный вызов ref() не имеет эффекта.
worker.resourceLimits
Предоставляет набор ограничений ресурсов движка JavaScript для данного потока рабочего процесса. Если опция 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('worker_threads').threadId. Это значение уникально для каждого экземпляра Worker внутри одного процесса.
worker.unref()
Вызов 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