Потоки Worker
Исходный код: lib/worker_threads.js
Модуль node:worker_threads позволяет использовать потоки, выполняющие JavaScript параллельно. Чтобы получить к нему доступ:
Модули JavaScript
import worker_threads from 'node:worker_threads';
CommonJS
'use strict';
const worker_threads = require('node:worker_threads');Потоки Worker полезны для выполнения операций JavaScript, интенсивно использующих процессор. Для задач с интенсивным вводом-выводом они малоэффективны. Встроенные асинхронные операции ввода-вывода Node.js эффективнее потоков Worker.
В отличие от child_process или cluster, worker_threads могут совместно использовать память. Это можно сделать, передав экземпляры ArrayBuffer или совместно используя экземпляры SharedArrayBuffer.
Модули JavaScript
import {
Worker,
isMainThread,
parentPort,
workerData,
} from 'node:worker_threads';
if (!isMainThread) {
const { parse } = await import('some-js-parsing-library');
const script = workerData;
parentPort.postMessage(parse(script));
}
export default function parseJSAsync(script) {
return new Promise((resolve, reject) => {
const worker = new Worker(new URL(import.meta.url), {
workerData: script,
});
worker.on('message', resolve);
worker.once('error', reject);
worker.once('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`));
});
});
};CommonJS
'use strict';
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.once('error', reject);
worker.once('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));
}В приведённом выше примере для каждого вызова parseJSAsync() создаётся поток Worker. На практике для таких задач следует использовать пул потоков Worker. В противном случае затраты на создание потоков Worker, вероятно, превысят получаемую от них пользу.
При реализации пула потоков Worker используйте API AsyncResource, чтобы уведомить диагностические инструменты (например, для предоставления асинхронных трассировок стека) о взаимосвязи между задачами и их результатами. Пример реализации см. в разделе «Использование AsyncResource для пула потоков Worker» документации async_hooks.
По умолчанию потоки Worker наследуют параметры, не относящиеся к конкретному процессу. См. раздел Worker constructor options, чтобы узнать, как настроить параметры потока Worker, в частности параметры argv и execArgv.
worker_threads.getEnvironmentData(key)
-
key<any> Любое произвольное клонируемое значение JavaScript, которое можно использовать в качестве ключа <Map>. - Возвращает: <any>
В потоке Worker worker.getEnvironmentData() возвращает копию данных, переданных в worker.setEnvironmentData() потока, создавшего его. Каждый новый Worker автоматически получает собственную копию данных окружения.
Модули JavaScript
import {
Worker,
isMainThread,
setEnvironmentData,
getEnvironmentData,
} from 'node:worker_threads';
if (isMainThread) {
setEnvironmentData('Hello', 'World!');
const worker = new Worker(new URL(import.meta.url));
} else {
console.log(getEnvironmentData('Hello')); // Prints 'World!'.
}CommonJS
'use strict';
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!'.
}
worker_threads.isInternalThread
- Тип: <boolean>
Равно true, если этот код выполняется во внутреннем потоке Worker (например, в потоке загрузчика).
node --experimental-loader ./loader.js main.js copy
Модули JavaScript
// loader.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread); // trueCommonJS
// loader.js
'use strict';
const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread); // trueМодули JavaScript
// main.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread); // falseCommonJS
// main.js
'use strict';
const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread); // false
worker_threads.isMainThread
- Тип: <boolean>
Равно true, если этот код выполняется не в потоке Worker.
Модули JavaScript
import { Worker, isMainThread } from 'node:worker_threads';
if (isMainThread) {
// This re-loads the current file inside a Worker instance.
new Worker(new URL(import.meta.url));
} else {
console.log('Inside Worker!');
console.log(isMainThread); // Prints 'false'.
}CommonJS
'use strict';
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'.
}
worker_threads.markAsUntransferable(object)
-
object<any> Любое произвольное значение JavaScript.
Помечает объект как непередаваемый. Если object указан в списке передачи вызова port.postMessage(), возникает ошибка. Ничего не делает, если object — примитивное значение.
В частности, это полезно для объектов, которые можно клонировать, а не передавать, и которые используются другими объектами на стороне отправителя. Например, Node.js помечает таким образом ArrayBuffer, используемые в пуле Buffer.
Эту операцию нельзя отменить.
Модули JavaScript
import { MessageChannel, markAsUntransferable } from '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);CommonJS
'use strict';
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);В браузерах нет эквивалента этого API.
worker_threads.isMarkedAsUntransferable(object)
Проверяет, помечен ли объект как непередаваемый с помощью markAsUntransferable().
Модули JavaScript
import { markAsUntransferable, isMarkedAsUntransferable } from 'node:worker_threads';
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // Returns true.CommonJS
'use strict';
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads');
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // Returns true.В браузерах нет эквивалента этого API.
worker_threads.markAsUncloneable(object)
-
object<any> Любое произвольное значение JavaScript.
Помечает объект как неклонируемый. Если object используется в качестве message при вызове port.postMessage(), возникает ошибка. Ничего не делает, если object — примитивное значение.
Это не влияет на ArrayBuffer и любые объекты типа Buffer.
Эту операцию нельзя отменить.
Модули JavaScript
import { markAsUncloneable } from 'node:worker_threads';
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// This will throw an error, because anyObject is not cloneable.
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}CommonJS
'use strict';
const { markAsUncloneable } = require('node:worker_threads');
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// This will throw an error, because anyObject is not cloneable.
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}В браузерах нет эквивалента этого API.
worker_threads.moveMessagePortToContext(port, contextifiedSandbox)
-
port<MessagePort> Порт сообщений для передачи. -
contextifiedSandbox<Object> Контекстуализированный объект, возвращённый методомvm.createContext(). -
Возвращает: <MessagePort>
Передаёт MessagePort в другой контекст vm. Исходный объект port становится непригодным для использования, а возвращённый экземпляр MessagePort занимает его место.
Возвращённый MessagePort является объектом целевого контекста и наследуется от его глобального класса Object. Объекты, переданные обработчику port.onmessage(), также создаются в целевом контексте и наследуются от его глобального класса Object.
Однако созданный MessagePort больше не наследуется от <EventTarget>, и для получения событий с его помощью можно использовать только port.onmessage().
worker_threads.parentPort
- Тип: <null> | <MessagePort>
Если этот поток является Worker, это MessagePort, обеспечивающий связь с родительским потоком. Сообщения, отправленные с помощью parentPort.postMessage(), доступны в родительском потоке с помощью worker.on('message'), а сообщения, отправленные из родительского потока с помощью worker.postMessage(), доступны в этом потоке с помощью parentPort.on('message').
Модули JavaScript
import { Worker, isMainThread, parentPort } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
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);
});
}CommonJS
'use strict';
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);
});
}
worker_threads.postMessageToThread(threadId, value[, transferList][, timeout])
-
threadId<number> Идентификатор целевого потока. Если идентификатор потока недействителен, будет вызвана ошибкаERR_WORKER_MESSAGING_FAILED. Если идентификатор целевого потока совпадает с идентификатором текущего потока, будет вызвана ошибкаERR_WORKER_MESSAGING_SAME_THREAD. -
value<any> Отправляемое значение. -
transferList<Object[]> Если вvalueпередаются один или несколько объектов типаMessagePort, для этих элементов необходимо указатьtransferList, иначе будет вызвана ошибкаERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST. Подробнее см. в разделеport.postMessage(). -
timeout<number> Время ожидания доставки сообщения в миллисекундах. По умолчанию —undefined, что означает бесконечное ожидание. Если время ожидания операции истечёт, будет вызвана ошибкаERR_WORKER_MESSAGING_TIMEOUT. - Возвращает: <Promise> Промис, который выполняется, если целевой поток успешно обработал сообщение.
Отправляет значение другому потоку Worker, указанному по идентификатору потока.
Если в целевом потоке нет обработчика события workerMessage, операция вызовет ошибку ERR_WORKER_MESSAGING_FAILED.
Если при обработке события workerMessage в целевом потоке возникла ошибка, операция вызовет ошибку ERR_WORKER_MESSAGING_ERRORED.
Этот метод следует использовать, если целевой поток не является непосредственным родительским или дочерним потоком текущего. Если потоки связаны отношением родитель—потомок, используйте require('node:worker_threads').parentPort.postMessage() и worker.postMessage() для связи между потоками.
В примере ниже показано использование postMessageToThread: создаются 10 вложенных потоков, и последний пытается связаться с главным потоком.
Модули JavaScript
import process from 'node:process';
import {
postMessageToThread,
threadId,
workerData,
Worker,
} from 'node:worker_threads';
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(new URL(import.meta.url), {
workerData: { level: level + 1 },
});
}
if (level === 0) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
postMessageToThread(source, { message: 'pong' });
});
} else if (level === 10) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
channel.postMessage('done');
channel.close();
});
await postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;CommonJS
'use strict';
const process = require('node:process');
const {
postMessageToThread,
threadId,
workerData,
Worker,
} = require('node:worker_threads');
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(__filename, {
workerData: { level: level + 1 },
});
}
if (level === 0) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
postMessageToThread(source, { message: 'pong' });
});
} else if (level === 10) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
channel.postMessage('done');
channel.close();
});
postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;
worker_threads.receiveMessageOnPort(port)
-
port<MessagePort> | <BroadcastChannel> -
Возвращает: <Object> | <undefined>
Получает одно сообщение из указанного MessagePort. Если сообщений нет, возвращается undefined; в противном случае возвращается объект с единственным свойством message, содержащим полезную нагрузку сообщения, соответствующего самому старому сообщению в очереди MessagePort.
Модули JavaScript
import { MessageChannel, receiveMessageOnPort } from '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: undefinedCommonJS
'use strict';
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При использовании этой функции событие 'message' не генерируется, а обработчик onmessage не вызывается.
worker_threads.resourceLimits
- Тип: <Object>
Предоставляет набор ограничений на ресурсы движка JS в этом потоке Worker. Если конструктору Worker был передан параметр resourceLimits, здесь будут указаны соответствующие значения.
При использовании в главном потоке возвращается пустой объект.
worker_threads.SHARE_ENV
- Тип: <symbol>
Специальное значение, которое можно передать в качестве параметра env конструктора Worker, чтобы указать, что текущий поток и поток Worker должны совместно использовать один и тот же набор переменных окружения с доступом на чтение и запись.
Модули JavaScript
import process from 'node:process';
import { Worker, SHARE_ENV } from 'node:worker_threads';
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
.once('exit', () => {
console.log(process.env.SET_IN_WORKER); // Prints 'foo'.
});CommonJS
'use strict';
const { Worker, SHARE_ENV } = require('node:worker_threads');
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
.once('exit', () => {
console.log(process.env.SET_IN_WORKER); // Prints 'foo'.
});
worker_threads.setEnvironmentData(key[, value])
-
key<any> Любое произвольное клонируемое значение JavaScript, которое можно использовать в качестве ключа <Map>. -
value<any> Любое произвольное клонируемое значение JavaScript, которое будет клонировано и автоматически передано всем новым экземплярамWorker. Если в качествеundefinedпереданоvalue, ранее заданное значение дляkeyбудет удалено.
API worker.setEnvironmentData() задаёт содержимое worker.getEnvironmentData() в текущем потоке и во всех новых экземплярах Worker, созданных в текущем контексте.
worker_threads.threadId
- Тип: <integer>
Целочисленный идентификатор текущего потока. В соответствующем объекте Worker (если он существует) он доступен как worker.threadId. Это значение уникально для каждого экземпляра Worker в пределах одного процесса.
worker_threads.threadName
Строковый идентификатор текущего потока или null, если поток не запущен. В соответствующем объекте Worker (если он существует) он доступен как worker.threadName.
worker_threads.workerData
Произвольное значение JavaScript, содержащее копию данных, переданных конструктору Worker этого потока.
Данные клонируются так же, как при использовании postMessage(), в соответствии с алгоритмом структурного клонирования HTML.
Модули JavaScript
import { Worker, isMainThread, workerData } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url), { workerData: 'Hello, world!' });
} else {
console.log(workerData); // Prints 'Hello, world!'.
}CommonJS
'use strict';
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!'.
}
worker_threads.locks
Экземпляр LockManager, который можно использовать для координации доступа к ресурсам, совместно используемым несколькими потоками одного процесса. Семантика этого API соответствует семантике браузерного LockManager
Класс: Lock
Интерфейс Lock предоставляет сведения о блокировке, полученной с помощью locks.request()
Класс: LockManager
Интерфейс LockManager предоставляет методы для запроса блокировок и получения сведений о них. Чтобы получить экземпляр LockManager, используйте
Модули JavaScript
import { locks } from 'node:worker_threads';CommonJS
'use strict';
const { locks } = require('node:worker_threads');Эта реализация соответствует API браузерного LockManager.
locks.request(name[, options], callback)
-
name<string> -
options<Object>-
mode<string>'exclusive'или'shared'. По умолчанию:'exclusive'. -
ifAvailable<boolean> Если значение равноtrue, запрос будет удовлетворён, только если блокировка ещё не установлена. Если запрос нельзя удовлетворить, будет вызванcallbackсо значениемnullвместо экземпляраLock. По умолчанию:false. -
steal<boolean> Если значение равноtrue, все существующие блокировки с тем же именем снимаются, а запрос выполняется немедленно, опережая запросы в очереди. По умолчанию:false. -
signal<AbortSignal>, который можно использовать для отмены ожидающего (ещё не удовлетворённого) запроса блокировки.
-
-
callback<Function> Вызывается после получения блокировки (или немедленно со значениемnull, еслиifAvailableравноtrueи блокировка недоступна). Блокировка снимается автоматически при возврате функции или, если функция возвращает промис, после его завершения. - Возвращает: <Promise> Выполняется после снятия блокировки.
Модули JavaScript
import { locks } from 'node:worker_threads';
await locks.request('my_resource', async (lock) => {
// The lock has been acquired.
});
// The lock has been released here.CommonJS
'use strict';
const { locks } = require('node:worker_threads');
locks.request('my_resource', async (lock) => {
// The lock has been acquired.
}).then(() => {
// The lock has been released here.
});
locks.query()
- Возвращает: <Promise>
Выполняется с объектом LockManagerSnapshot, описывающим удерживаемые и ожидающие блокировки текущего процесса.
Модули JavaScript
import { locks } from 'node:worker_threads';
const snapshot = await locks.query();
for (const lock of snapshot.held) {
console.log(`held lock: name ${lock.name}, mode ${lock.mode}`);
}
for (const pending of snapshot.pending) {
console.log(`pending lock: name ${pending.name}, mode ${pending.mode}`);
}CommonJS
'use strict';
const { locks } = require('node:worker_threads');
locks.query().then((snapshot) => {
for (const lock of snapshot.held) {
console.log(`held lock: name ${lock.name}, mode ${lock.mode}`);
}
for (const pending of snapshot.pending) {
console.log(`pending lock: name ${pending.name}, mode ${pending.mode}`);
}
});Класс: BroadcastChannel extends EventTarget
Экземпляры BroadcastChannel обеспечивают асинхронную связь «один ко многим» со всеми другими экземплярами BroadcastChannel, подключёнными к каналу с тем же именем.
Модули JavaScript
import {
isMainThread,
BroadcastChannel,
Worker,
} from '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(new URL(import.meta.url));
} else {
bc.postMessage('hello from every worker');
bc.close();
}CommonJS
'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();
}
new BroadcastChannel(name)
-
name<any> Имя канала для подключения. Допускается любое значение JavaScript, которое можно преобразовать в строку с помощью`${name}`.
broadcastChannel.close()
Закрывает соединение BroadcastChannel.
broadcastChannel.onmessage
- Тип: <Function> Вызывается с одним аргументом
MessageEventпри получении сообщения.
broadcastChannel.onmessageerror
- Тип: <Function> Вызывается, если полученное сообщение невозможно десериализовать.
broadcastChannel.postMessage(message)
-
message<any> Любое клонируемое значение 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.
Модули JavaScript
import { MessageChannel } from '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')` listenerCommonJS
'use strict';
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Класс: MessagePort
- Наследует: <EventTarget>
Экземпляры класса worker.MessagePort представляют один конец асинхронного двустороннего канала связи. Он может использоваться для передачи структурированных данных, областей памяти и других MessagePort между разными Worker.
Эта реализация соответствует MessagePort браузера.
Событие: 'close'
Событие 'close' генерируется при отключении любой из сторон канала.
Модули JavaScript
import { MessageChannel } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
// Prints:
// foobar
// closed!
port2.on('message', (message) => console.log(message));
port2.once('close', () => console.log('closed!'));
port1.postMessage('foobar');
port1.close();CommonJS
'use strict';
const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
// Prints:
// foobar
// closed!
port2.on('message', (message) => console.log(message));
port2.once('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, напримерRegExp,BigInt,Map,Setи т. д. -
valueможет содержать типизированные массивы, использующие какArrayBuffer, так иSharedArrayBuffer. -
valueможет содержать экземплярыWebAssembly.Module. -
valueне может содержать нативные объекты (на основе C++), за исключением следующих:
Модули JavaScript
import { MessageChannel } from '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);CommonJS
'use strict';
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);transferList может быть списком объектов <ArrayBuffer>, MessagePort и FileHandle. После передачи они становятся недоступны на отправляющей стороне канала (даже если не содержатся в value). В отличие от дочерних процессов, передача таких дескрипторов, как сетевые сокеты, в настоящее время не поддерживается.
Если value содержит экземпляры <SharedArrayBuffer>, они доступны из любого потока. Их нельзя включать в transferList.
value может по-прежнему содержать экземпляры ArrayBuffer, не включенные в transferList; в этом случае базовая память копируется, а не перемещается.
Модули JavaScript
import { MessageChannel } from '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 ]);CommonJS
'use strict';
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 ]);Объект сообщения клонируется немедленно, поэтому его можно изменить после отправки без побочных эффектов.
Дополнительные сведения о механизмах сериализации и десериализации, лежащих в основе этого API, см. в API сериализации модуля node:v8.
Особенности передачи TypedArray и Buffer
Все экземпляры <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 см. в разделе Buffer.allocUnsafe().
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()
- Возвращает: <boolean>
Если значение равно true, объект MessagePort не позволит циклу событий Node.js завершиться.
port.ref()
Противоположность unref(). Вызов ref() для порта, ранее переведенного в состояние unref(), не позволит программе завершиться, если это единственный оставшийся активный дескриптор (поведение по умолчанию). Если порт переведен в состояние ref(), повторный вызов ref() не повлияет на результат.
Если обработчики добавляются или удаляются с помощью .on('message'), порт автоматически переводится в состояние ref() или unref() в зависимости от наличия обработчиков событий.
port.start()
Начинает принимать сообщения через этот MessagePort. При использовании этого порта в качестве генератора событий метод вызывается автоматически после добавления обработчиков 'message'.
Этот метод существует для соответствия API Web 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 в другой поток через уже существующий канал, например глобальный.
Дополнительные сведения о передаче сообщений и о том, какие значения JavaScript можно успешно передавать между потоками, см. в разделе port.postMessage().
Модули JavaScript
import assert from 'node:assert';
import {
Worker, MessageChannel, MessagePort, isMainThread, parentPort,
} from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
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();
});
}CommonJS
'use strict';
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();
});
}
new Worker(filename[, options])
-
filename<string> | <URL> Путь к основному скрипту или модулю Worker. Должен быть абсолютным или относительным (то есть относительно текущего рабочего каталога) путём, начинающимся с./или../, либо объектом WHATWGURLс протоколомfile:илиdata:. При использовании URLdata:данные интерпретируются на основе MIME-типа с помощью загрузчика модулей ECMAScript. Еслиoptions.evalимеет значениеtrue, это строка с кодом JavaScript, а не путь. -
options<Object>-
argv<any[]> Список аргументов, которые будут преобразованы в строки и добавлены кprocess.argvв Worker. В основном это аналогworkerData, но значения доступны в глобальном объектеprocess.argvтак, как если бы они были переданы скрипту в качестве параметров CLI. -
env<Object> Если задано, определяет начальное значениеprocess.envв потоке Worker. В качестве специального значения можно использоватьworker.SHARE_ENV, чтобы указать, что родительский и дочерний потоки должны совместно использовать переменные окружения; в этом случае изменения объектаprocess.envодного потока также влияют на другой поток. По умолчанию:process.env. -
eval<boolean> Если имеет значениеtrueи первый аргумент —string, первый аргумент конструктора интерпретируется как скрипт, который выполняется после перехода Worker в состояние готовности. -
execArgv<string[]> Список параметров CLI Node, передаваемых Worker. Параметры V8 (например,--max-old-space-size) и параметры, влияющие на процесс (например,--title), не поддерживаются. Если задано, это значение предоставляется в Worker какprocess.execArgv. По умолчанию параметры наследуются от родительского потока. -
stdin<boolean> Если задано значениеtrue,worker.stdinпредоставляет поток для записи, содержимое которого будет доступно в Worker какprocess.stdin. По умолчанию данные не предоставляются. -
stdout<boolean> Если задано значениеtrue,worker.stdoutне передаётся автоматически вprocess.stdoutродительского потока. -
stderr<boolean> Если задано значениеtrue,worker.stderrне передаётся автоматически вprocess.stderrродительского потока. -
workerData<any> Любое значение JavaScript, которое клонируется и становится доступным какrequire('node:worker_threads').workerData. Клонирование выполняется согласно алгоритму структурированного клонирования HTML; если объект нельзя клонировать (например, если он содержитfunction), возникает ошибка. -
trackUnmanagedFds<boolean> Если задано значениеtrue, Worker отслеживает необработанные файловые дескрипторы, управляемые с помощьюfs.open()иfs.close(), и закрывает их при завершении работы Worker — так же, как другие ресурсы, например сетевые сокеты или файловые дескрипторы, управляемые через APIFileHandle. Этот параметр автоматически наследуется всеми вложеннымиWorker. По умолчанию:true. -
transferList<Object[]> Если вworkerDataпередан один или несколько объектов типаMessagePort, для этих элементов требуетсяtransferList, иначе возникает ошибкаERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST. Дополнительные сведения см. в разделеport.postMessage(). -
resourceLimits<Object> Необязательный набор ограничений ресурсов для нового экземпляра движка JS. Достижение этих ограничений приводит к завершению экземпляраWorker. Ограничения затрагивают только движок JS и не распространяются на внешние данные, включаяArrayBuffer. Даже при заданных ограничениях процесс может аварийно завершиться при глобальной нехватке памяти.-
maxOldGenerationSizeMb<number> Максимальный размер основной кучи в МБ. Если задан аргумент командной строки--max-old-space-size, он переопределяет это значение. -
maxYoungGenerationSizeMb<number> Максимальный размер области кучи для недавно созданных объектов. Если задан аргумент командной строки--max-semi-space-size, он переопределяет это значение. -
codeRangeSizeMb<number> Размер предварительно выделенного диапазона памяти, используемого для сгенерированного кода. -
stackSizeMb<number> Максимальный размер стека по умолчанию для потока. При малых значениях экземпляры Worker могут стать непригодны для использования. По умолчанию:4.
-
-
name<string> Необязательное значениеname, которое подставляется в имя потока и заголовок Worker для отладки и идентификации; итоговый заголовок имеет вид[worker ${id}] ${name}. Максимально допустимый размер параметра зависит от операционной системы. Если переданное имя превышает ограничение, оно будет усечено.- Максимальная длина:
- Windows: 32 767 символов
- macOS: 64 символа
- Linux: 16 символов
- NetBSD: ограничено значением
PTHREAD_MAX_NAMELEN_NP - FreeBSD и OpenBSD: ограничено значением
MAXCOMLENПо умолчанию:'WorkerThread'.
- Максимальная длина:
-
Событие: 'error'
-
err<any>
Событие 'error' возникает, если в потоке Worker выбрасывается необработанное исключение. В этом случае Worker завершается.
Событие: 'exit'
-
exitCode<integer>
Событие 'exit' возникает после остановки Worker. Если Worker завершился вызовом process.exit(), параметр exitCode содержит переданный код завершения. Если Worker был принудительно остановлен, параметр exitCode имеет значение 1.
Это последнее событие, которое возникает у любого экземпляра Worker.
Событие: 'message'
-
value<any> Переданное значение
Событие 'message' возникает, когда поток Worker вызывает require('node:worker_threads').parentPort.postMessage(). Подробнее см. описание события port.on('message').
Все сообщения, отправленные из потока Worker, обрабатываются до возникновения события 'exit' объекта Worker.
Событие: 'messageerror'
-
error<Error> Объект Error
Событие 'messageerror' возникает, если не удалось десериализовать сообщение.
Событие: 'online'
Событие 'online' возникает, когда поток Worker начинает выполнять код JavaScript.
worker.cpuUsage([prev])
- Возвращает: <Promise>
Этот метод возвращает Promise, который разрешается объектом, идентичным результату process.threadCpuUsage(), либо отклоняется с ошибкой ERR_WORKER_NOT_RUNNING, если Worker больше не работает. Этот метод позволяет получать статистику извне самого потока.
worker.getHeapSnapshot([options])
-
options<Object> - Возвращает: <Promise> обещание, результатом которого является поток для чтения со снимком кучи V8
Возвращает поток для чтения со снимком текущего состояния Worker в V8. Дополнительные сведения см. в разделе v8.getHeapSnapshot().
Если поток Worker больше не работает (это может произойти до возникновения события 'exit'), возвращённое Promise немедленно отклоняется с ошибкой ERR_WORKER_NOT_RUNNING.
worker.getHeapStatistics()
- Возвращает: <Promise>
Этот метод возвращает Promise, который разрешается объектом, идентичным результату v8.getHeapStatistics(), либо отклоняется с ошибкой ERR_WORKER_NOT_RUNNING, если Worker больше не работает. Этот метод позволяет получать статистику извне самого потока.
worker.performance
Объект, с помощью которого можно запрашивать сведения о производительности экземпляра Worker.
performance.eventLoopUtilization([utilization1[, utilization2]])
-
utilization1<Object> Результат предыдущего вызоваeventLoopUtilization(). -
utilization2<Object> Результат предыдущего вызоваeventLoopUtilization(), выполненного доutilization1. - Возвращает: <Object>
Выполняет то же, что и perf_hooks eventLoopUtilization(), но возвращает значения экземпляра Worker.
Одно из отличий состоит в том, что, в отличие от основного потока, инициализация Worker происходит в цикле событий. Поэтому загрузка цикла событий доступна сразу после начала выполнения скрипта Worker.
Отсутствие увеличения времени idle не означает, что Worker завис при инициализации. В следующем примере за всё время работы Worker не накапливается время idle, но он по-прежнему может обрабатывать сообщения.
Модули JavaScript
import { Worker, isMainThread, parentPort } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
setInterval(() => {
worker.postMessage('hi');
console.log(worker.performance.eventLoopUtilization());
}, 100).unref();
} else {
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);
}CommonJS
'use strict';
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();
} else {
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);
}Загрузка цикла событий Worker доступна только после возникновения события 'online'. Если вызвать этот метод до данного события или после события 'exit', все свойства будут иметь значение 0.
worker.postMessage(value[, transferList])
-
value<any> -
transferList<Object[]>
Отправляет сообщение Worker, которое принимается через require('node:worker_threads').parentPort.on('message'). Дополнительные сведения см. в разделе port.postMessage().
worker.ref()
Действие, противоположное unref(): вызов ref() для ранее Worker, к которому был применён unref(), не позволяет программе завершиться, если Worker остаётся единственным активным дескриптором (поведение по умолчанию). Если к Worker был применён ref(), повторный вызов ref() не оказывает никакого эффекта.
worker.resourceLimits
- Тип: <Object>
Предоставляет набор ограничений ресурсов движка JS для этого потока Worker. Если конструктору Worker был передан параметр resourceLimits, эти значения соответствуют ему.
Если Worker остановлен, возвращается пустой объект.
worker.startCpuProfile()
- Возвращает: <Promise>
Запускает профилирование CPU и возвращает Promise, который выполняется с ошибкой или объектом CPUProfileHandle. Этот API поддерживает синтаксис await using.
const { Worker } = require('node:worker_threads');
const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
worker.on('online', async () => {
const handle = await worker.startCpuProfile();
const profile = await handle.stop();
console.log(profile);
worker.terminate();
}); copy Пример await using.
const { Worker } = require('node:worker_threads');
const w = new Worker(`
const { parentPort } = require('node:worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// Stop profile automatically when return and profile will be discarded
await using handle = await w.startCpuProfile();
}); copy
worker.startHeapProfile()
- Возвращает: <Promise>
Запускает профилирование кучи и возвращает Promise, который выполняется с ошибкой или объектом HeapProfileHandle. Этот API поддерживает синтаксис await using.
const { Worker } = require('node:worker_threads');
const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
worker.on('online', async () => {
const handle = await worker.startHeapProfile();
const profile = await handle.stop();
console.log(profile);
worker.terminate();
}); copy Пример await using.
const { Worker } = require('node:worker_threads');
const w = new Worker(`
const { parentPort } = require('node:worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// Stop profile automatically when return and profile will be discarded
await using handle = await w.startHeapProfile();
}); copy
worker.stderr
- Тип: <stream.Readable>
Это поток для чтения, содержащий данные, записанные в process.stderr внутри потока Worker. Если параметр stderr: true не был передан конструктору Worker, данные передаются в поток process.stderr родительского потока.
worker.stdin
- Тип: <null> | <stream.Writable>
Если конструктору Worker был передан параметр stdin: true, это поток для записи. Записанные в этот поток данные будут доступны в потоке Worker как process.stdin.
worker.stdout
- Тип: <stream.Readable>
Это поток для чтения, содержащий данные, записанные в process.stdout внутри потока Worker. Если параметр stdout: true не был передан конструктору Worker, данные передаются в поток process.stdout родительского потока.
worker.terminate()
- Возвращает: <Promise>
Как можно скорее останавливает выполнение всего кода JavaScript в потоке Worker. Возвращает Promise с кодом завершения, который выполняется при возникновении события 'exit'.
worker.threadId
- Тип: <integer>
Целочисленный идентификатор указанного потока. Внутри потока Worker он доступен как require('node:worker_threads').threadId. Это значение уникально для каждого экземпляра Worker в рамках одного процесса.
worker.threadName
Строковый идентификатор указанного потока или null, если поток не работает. Внутри потока Worker он доступен как require('node:worker_threads').threadName.
worker.unref()
Вызов unref() для Worker позволяет потоку завершиться, если он является единственным активным дескриптором в системе событий. Если к Worker уже был применён unref(), повторный вызов unref() не оказывает никакого эффекта.
worker[Symbol.asyncDispose]()
Вызывает worker.terminate() при выходе из области действия освобождения ресурсов.
async function example() {
await using worker = new Worker('for (;;) {}', { eval: true });
// Worker is automatically terminate when the scope is exited.
} copy Примечания
Синхронная блокировка стандартных потоков ввода-вывода
Worker используют передачу сообщений через <MessagePort> для реализации взаимодействия с stdio. Это означает, что вывод stdio, поступающий из Worker, может быть заблокирован синхронным кодом на принимающей стороне, который блокирует цикл событий Node.js.
Модули JavaScript
import {
Worker,
isMainThread,
} from 'node: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');
}CommonJS
'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 из скриптов предварительной загрузки
Будьте осторожны при запуске потоков Worker из скриптов предварительной загрузки (скриптов, загружаемых и выполняемых с помощью флага командной строки -r). Если параметр execArgv явно не задан, новые потоки Worker автоматически наследуют флаги командной строки запущенного процесса и предварительно загружают те же скрипты предварительной загрузки, что и основной поток. Если скрипт предварительной загрузки безусловно запускает поток 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/dist/latest-v24.x/docs/api/worker_threads.html