Основная информация
Автор протестировал эту функцию на последней разрабатываемой версии Node.js v11.4.0. В настоящее время необходимо добавить флаг, чтобы представить ее.Worker Threads
,Например:
node --experimental-worker index.js
Worker Threads
Функции были представлены в версии 10.5.0 20 июня 2018 г.:
В настоящее время модуль находится вStability 1 - Experimentalэтап, изменения будут больше,не предлагаетсяДля производственной среды.
интерфейс модуля
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
В этом модуле очень мало объектов и классов, всего 4 объекта и 3 класса.
-
isMainThread
: false означает, что это в настоящее время рабочая нить,false
Представляет основной поток -
parentPort
: в рабочем потоке представляет родительский процесс.MessagePort
объект типа, в основном потоке какnull
-
workerData
: В рабочем потоке это данные инициализации, когда родительский процесс создает рабочий поток, в основном потоке этоundefined
-
threadId
: идентификатор потока в рабочем потоке, идентификатор потока в родительском процессе.0
. -
MessageChannel
: Содержит два потока, которые уже могут взаимодействовать друг с другом.MessagePort
Типовые объекты, которые можно использовать для создания пользовательских каналов связи, см. примеры реализации. -
MessagePort
: дескриптор межпотокового взаимодействия, унаследованныйEventEmitter
, включая событие close message для получения сообщений о закрытии и отправке объектов, а также такие операции, как close postMessage. -
Worker
: Тип объекта, используемый основным потоком для создания рабочих потоков, включая все операции MessagePort и некоторые определенные операции с метаданными подпотока. Первый параметр конструктора — это программа-скрипт входа, выполняемая дочерним потоком, а второй параметр содержит некоторые элементы конфигурации, которые могут указывать некоторые начальные параметры. Подробнее см.Документация
Изменения в модели памяти
в настоящее время используетcluster
иchild_process
Во время нормального использованияSharedArrayBuffer
Для реализации памяти, которая должна совместно использоваться несколькими процессами.
port.postMessage(value[, transferList])
Теперь модуль Worker Threads не рекомендует использовать многопотоковую разделяемую память на уровне API, значение первого значения параметра будет клонировано в поток, получающий сообщение. TransferList может быть передан толькоArrayBuffer
илиMessagePort
объект, прошелArrayBuffer
Изменяет права доступа к буферу для потока, который принимает сообщение, передаваяMessagePort
Вы можете обратиться ко второму примеру.
Все коммуникационные сообщения между потоками сериализуются для достижения базовой версии 8, отношений, стандартов Web Worker, более конкретных рабочих потоков и моделей v8, а также многопоточного браузера и еще не запущены.
Пример 1: счетчик связи между основным потоком и рабочим потоком, после того как счетчик достигает 5, рабочий поток совершает самоубийство
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
function mainThread() {
const worker = new Worker(__filename, { workerData: 0 });
worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); });
worker.on('message', msg => {
console.log(`main: receive ${msg}`);
worker.postMessage(msg + 1);
});
}
function workerThread() {
console.log(`worker: threadId ${threadId} start with ${__filename}`);
console.log(`worker: workerDate ${workerData}`);
parentPort.on('message', msg => {
console.log(`worker: receive ${msg}`);
if (msg === 5) { process.exit(); }
parentPort.postMessage(msg);
}),
parentPort.postMessage(workerData);
}
if (isMainThread) {
mainThread();
} else {
workerThread();
}
Выходной результат:
worker: threadId 1 start with /Users/azard/test/index.js
worker: workerDate 0
main: receive 0
worker: receive 1
main: receive 1
worker: receive 2
main: receive 2
worker: receive 3
main: receive 3
worker: receive 4
main: receive 4
worker: receive 5
main: receive 5
main: worker stopped with exit code 0
Пример 2. Используйте MessageChannel, чтобы позволить двум дочерним потокам взаимодействовать напрямую
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
if (isMainThread) {
const worker1 = new Worker(__filename);
const worker2 = new Worker(__filename);
const subChannel = new MessageChannel();
worker1.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
worker2.postMessage({ hereIsYourPort: subChannel.port2 }, [subChannel.port2]);
} else {
parentPort.once('message', (value) => {
value.hereIsYourPort.postMessage('hello');
value.hereIsYourPort.on('message', msg => {
console.log(`thread ${threadId}: receive ${msg}`);
});
});
}
вывод:
thread 2: receive hello
thread 1: receive hello
Суммировать
Теперь, когда Node.js имеет настоящую многопоточность, нет необходимости использовать кластер или многопроцессорный процесс child_process для решения некоторых проблем.Связанная модель фреймворка и библиотеки также может итеративно обновляться после того, как рабочие потоки станут стабильными.