
Друзья, знакомые с js, знают, что js 是单线程. В Node принята многопроцессная однопоточная модель. Из-за однопоточного ограничения JavaScript на многоядерных серверах нам часто приходится запускать несколько процессов, чтобы максимизировать производительность сервера.
Кластеры процессов Node.js можно использовать для запуска нескольких экземпляров Node.js, которые могут распределять рабочую нагрузку между потоками своих приложений. Если изоляция процесса не требуется, используйте вместо него модуль worker_threads , который позволяет запускать несколько потоков приложения в одном экземпляре Node.js.
Node представил модуль кластера после версии V0.8,一个主进程(master) 管理多个子进程(worker) 的方式实现集群.
Модуль кластера позволяет легко создавать дочерние процессы, которые используют общие порты сервера.
Нижний уровень кластера — это модуль child_process. Помимо отправки обычных сообщений, он также может отправлять базовые объекты
TCP,UDPи т. д. Модульclusterпредставляет собой комбинированное приложение модуляchild_processи модуляnet. При запуске кластера TCP-сервер будет запущен внутренне и файловый дескриптор сокета TCP-сервера будет отправлен в рабочий процесс.
В приложении модуля cluster一个主进程只能管理一组工作进程. Его режим работы не такой гибкий, как у модуля child_process , но он более стабилен:

const cluster = require('cluster') и комплексными .isMaster идентифицирует основной процесс, Node<16.isPrimary.isPrimary основной процесс, Node>16.isWorker.isWorker подпроцесс. .worker.worker за текущую работу. Ссылка на объект процесса [в дочернем процессе].workers хранит хеш активного объекта рабочего процесса с полем id в качестве ключа. Это упрощает циклическое перебор всех рабочих процессов. Он доступен только в основном процессе. cluster.wokers[id] === worker [в основном процессе]..settings доступен только для чтения, элемент конфигурации кластера. После вызова метода .setupPrimary() или .fork() этот объект настроек будет содержать настройки, включая значения по умолчанию. Ранее пустой объект. Этот объект не следует изменять или устанавливать вручную.cluster.settings :- `execArgv` <string[]>Список строковых параметров, передаваемых в исполняемый файл Node.js. **По умолчанию:** `process.execArgv`. - `exec` <строка> Путь к файлу рабочего процесса. **По умолчанию:** `process.argv[1]`. - `args` <string[]> Строковые аргументы, передаваемые рабочему процессу. **По умолчанию:** `process.argv.slice(2)`. - `cwd` <строка>Текущий рабочий каталог рабочего процесса. **По умолчанию:** «не определено» (унаследовано от родительского процесса). - `serialization` <строка>Указывает тип сериализации, используемый для отправки сообщений между процессами. Возможные значения: json и Advanced. **По умолчанию:** `false`. - `silent` <boolean>Отправлять ли вывод на стандартный ввод и вывод родительского процесса. **По умолчанию:** `false`. - `stdio` <Array> настраивает стандартный ввод и вывод порожденного процесса. Поскольку для запуска модуля кластера используется IPC, эта конфигурация должна содержать запись `'ipc'`. Когда эта опция предусмотрена, она переопределяет `тихий`. - `uid` <номер> устанавливает идентификатор пользователя процесса. - `gid` <номер> устанавливает идентификатор группы процесса. - `inspectPort` <номер> <Функция> Устанавливает порт инспектора для рабочего процесса. Это может быть число или функция, которая не принимает параметров и возвращает число. По умолчанию каждый рабочий процесс имеет свой собственный порт, начиная с `process.debugPort` основного процесса и увеличивая его. - `windowsHide` <boolean> Скрыть порожденное окно консоли процесса, обычно создаваемое в системах Windows. **По умолчанию:** `false`.
.fork([env]) порождает новый рабочий процесс [в основном процессе]..setupPrimary([settings]) Node>16.setupMaster([settings]) используется для изменения поведения «вилки» по умолчанию, после использования настройки появятся в cluster.settings . Любые изменения настроек повлияют только на будущие вызовы .fork() , но не на запущенные рабочие процессы. Вышеуказанные значения по умолчанию применяются только к первому вызову. Число узлов меньше 16. [В основном процессе].disconnect([callback]) Вызывается, когда все рабочие процессы отключаются и закрывают дескрипторы. [В основном процессе]Чтобы сделать кластер более стабильным и надежным, модуль cluster также предоставляет множество событий Event:
'message' , инициируемых, когда главный процесс кластера получает сообщение от любого рабочего процесса.'exit' : когда какой-либо рабочий процесс завершается, модуль кластера запускает событие 'exit' .Cluster.on('exit', (работник, код, сигнал) => {
console.log('работник %d умер (%s). перезапуск...',
worker.process.pid, код сигнала ||);
кластер.вилка();
}); 'listening' , после вызова listen() из рабочего процесса, когда на сервере инициируется событие 'listening' , cluster в основном процессе также запускает событие 'listening' .Cluster.on('прослушивание', (работник, адрес) => {
консоль.log(
`Работник теперь подключен к ${address.address}:${address.port}`);
}); 'fork' , когда создается новый рабочий процесс, модуль кластера запускает событие 'fork' .Cluster.on('вилка', (работник) => {
timeouts[worker.id] = setTimeout(errorMsg, 2000);
}); 'setup' , вызываемое каждый раз при вызове .setupPrimary() .disconnect инициируется после отключения IPC-канала рабочего процесса. Когда рабочий процесс завершается нормально, завершается или вручную отключается откластера.on('disconnect', (worker) => {
console.log(`Работник #${worker.id} отключился`);
}); Объект Worker содержит всю общедоступную информацию и методы рабочего процесса. В основном процессе вы можете использовать cluster.workers для получения. В рабочем процессе для его получения можно использовать cluster.worker .
.id процесса. Каждому новому рабочему процессу присваивается свой уникальный идентификатор. Этот идентификатор хранится в id . Когда рабочий процесс активен, это ключ, который индексирует его в cluster.workers ..process Все рабочие процессы создаются с помощью child_process.fork() , а объект, возвращаемый этой функцией, сохраняется как .process . В рабочем процессе хранится глобальный process ..send(message[, sendHandle[, options]][, callback]) отправляет сообщение рабочему процессу или основному процессу, и вы можете выбрать использование дескриптора. В основном процессе это отправляет сообщение конкретному рабочему процессу. Это то же самое, что ChildProcess.send() . В рабочем процессе это отправляет сообщение основному процессу. Это то же самое, что process.send() ..destroy().kill([signal]) Эта функция убьет рабочий процесс. Функция kill() убивает рабочий процесс, не дожидаясь плавного отключения. Она ведет себя так же, как worker.process.kill() . Для обратной совместимости этот метод имеет псевдоним worker.destroy() ..disconnect([callback]) отправляется рабочему процессу, заставляя его вызвать собственный .disconnect() , который отключит все серверы, дождется событий 'close' на этих серверах, а затем отключит канал IPC..isConnect() Эта функция возвращает true если рабочий процесс подключен к своему основному процессу через канал IPC, в противном случае — false . Рабочие процессы после создания подключаются к своему главному процессу..isDead() Эта функция возвращает true если рабочий процесс завершился (из-за выхода или получения сигнала). В противном случае он возвращает false .Чтобы сделать кластер более стабильным и надежным, модуль cluster также предоставляет множество событий:
'message' в рабочем процессе.Cluster.workers[id].on('message', messageHandler); 'exit' : когда какой-либо рабочий процесс завершается,当前worker工作进程вызывает событие 'exit' .если (cluster.isPrimary) {
константный рабочий = кластер.форк();
worker.on('exit', (код, сигнал) => {
если (сигнал) {
console.log(`Работник был убит сигналом: ${signal}`);
} иначе если (код !== 0) {
console.log(`Работник завершил работу с кодом ошибки: ${code}`);
} еще {
console.log('Успех работника!');
}
});
} 'listening' , вызовите listen() из рабочего процесса, чтобы прослушать текущий рабочий процесс.кластер.fork().on('прослушивание', (адрес) => {
// Рабочий процесс прослушивает }); disconnect , которое срабатывает после отключения IPC-канала рабочего процесса. Когда рабочий процесс завершается нормально, завершается или вручную отключается откластера.fork().on('disconnect', () => {
//Ограничено запуском текущего рабочего объекта}); В Node межпроцессное взаимодействие (IPC) используется для реализации межпроцессного взаимодействия между основным процессом и подпроцессами. Взаимодействие между процессами осуществляется сквозным образом. .send() (a.send означает отправку сообщения в Send) для отправки сообщений и прослушивания событий message для сбора информации. Это реализовано cluster模块путем интеграции EventEmitter . Это также простой пример межпроцессного взаимодействия на официальном сайте
process.on('message') , process.send()child.on('message') , child.send()# кластер.isMaster
# кластер.форк()
# кластер.работники
# кластер.workers[id].on('message', messageHandler);
# кластер.workers[id].send();
#process.on('message', messageHandler);
# процесс.отправить();
const кластер = требуется ('кластер');
const http = require('http');
# Основной процесс if (cluster.isMaster) {
// Отслеживаем http-запросы
console.log(`Основной ${process.pid} запущен`);
пусть numReqs = 0;
// Подсчет запросов
функция messageHandler(msg) {
if (msg.cmd && msg.cmd === 'notifyRequest') {
numReqs += 1;
}
}
// Запускаем рабочие процессы и слушаем сообщения, содержащие notifyRequest
// Запуск мультипроцесса (количество ядер процессора)
// Создаем рабочий процесс.
const numCPUs = require('os').cpus().length;
for (let i = 0; i <numCPUs; i++) {
консоль.log(я)
кластер.вилка();
}
// основной процесс работника кластера взаимодействует с дочерними процессами for (const id в кластере.workers) {
// ***Прослушиваем события дочерних процессов Cluster.workers[id].on('message', messageHandler);
// ***Отправляем кластер.workers[id].send({ дочернему процессу
введите: 'masterToWorker',
от: 'мастер',
данные: {
число: Math.floor(Math.random() * 50)
}
});
}
Cluster.on('exit', (работник, код, сигнал) => {
console.log(`работник ${worker.process.pid} умер`);
});
} еще {
# Дочерние процессы // Рабочие процессы могут использовать любое TCP-соединение // В этом примере это HTTP-сервер // Рабочие процессы имеют http-сервер.
http.Server((req, res) => {
res.writeHead(200);
res.end('привет, мирn');
//******! ! ! ! Сообщите мастеру о запросе! ! ! ! ! ! *******
//****** Отправляем процесс.send({ cmd: 'notifyRequest' });
//****** Слушаем процесс.on('message', function(message) {
// ххххххх
})
}).слушать(8000);
console.log(`Работник ${process.pid} запущен`);
} 
Связь между процессами NodeJS включает только передачу сообщений и фактически не передает объекты.
Перед отправкой сообщения метод send() соберет сообщение в дескриптор и сообщение. Это сообщение будет сериализовано с помощью JSON.stringify . То есть при передаче дескриптора весь объект не будет передан. передаются по каналу IPC. Все они являются строками и восстанавливаются в объекты через JSON.parse после передачи.
Почему при разветвлении несколько процессов могут прослушивать один и тот же порт? В коде есть app.listen(port) .
Причина в том, что основной процесс отправляет дескриптор служебного объекта, принадлежащего основному процессу, нескольким подпроцессам через метод send(), поэтому для каждого подпроцесса после восстановления дескриптора они получают один и тот же служебный объект. Когда в сети делается запрос на сервер, служба процесса является вытесняющей, поэтому при прослушивании на том же порту не будет возникать никаких исключений.
# master.js
const fork = require('child_process').fork;
const cpus = require('os').cpus();
for (let i=0; i<cpus.length; i++) {
const работник = fork('worker.js');
console.log('рабочий процесс создан, pid: %s ppid: %s', worker.pid,process.pid);
} # рабочий.js
const http = require('http');
http.createServer((req, res) => {
res.end('Я рабочий, pid: ' +process.pid +', ppid: '+process.ppid);
}).listen(3000); В приведенном выше примере кода, когда консоль выполняет
node master.jsтолько один рабочий может прослушивать порт 3000, а остальные выдаютError: listen EADDRINUSE :::3000.
发送句柄между процессами после версии v0.5.9/**. * http://nodejs.cn/api/child_process.html#child_process_subprocess_send_message_sendhandle_options_callback * сообщение * дескриптор отправки */ subprocess.send(message, sendHandle)
После того, как канал IPC установлен между родительским и дочерним процессами, сообщение отправляется через метод отправки объекта подпроцесса.二个参数sendHandle 就是句柄,可以是TCP套接字、TCP服务器、UDP套接字等, чтобы решить описанную выше проблему занятости порта несколькими процессами, мы передаем сокет основного процесса дочернему процессу.
# мастер.js
const fork = require('child_process').fork;
const cpus = require('os').cpus();
const server = require('net').createServer();
сервер.прослушивать(3000);
процесс.title = 'мастер узла'
for (let i=0; i<cpus.length; i++) {
const работник = fork('worker.js');
# Передаем дескриптор work.send('server', server);
console.log('рабочий процесс создан, pid: %s ppid: %s', worker.pid,process.pid);
} // рабочий.js
пусть рабочий;
процесс.title = 'узел-работник'
процесс.он('сообщение', функция (сообщение, sendHandle) {
если (сообщение === 'сервер') {
рабочий = sendHandle;
worker.on('соединение', функция (сокет) {
console.log('Я рабочий, pid: ' +process.pid +', ppid: '+process.ppid)
});
}
}); Убедитесь, что консоль выполняет node master.js



Если вы разбираетесь cluster , вы знаете, что дочерние процессы создаются с помощью cluster.fork() . В Linux система изначально предоставляет метод fork , так почему же Node решает реализовать cluster模块самостоятельно, а не напрямую использовать собственный метод системы? Основными причинами являются следующие два момента:
Процесс форка контролирует один и тот же порт, что приводит к ошибкам занятости порта.
Между процессами форка отсутствует балансировка нагрузки, что легко может привести к феномену громового стада
cluster模块Первая проблема: мы определяем, является ли текущий процесс master进程, если да, то он прослушивает порт. Если нет, он представляется как worker进程fork и не прослушивает порт.
В ответ на второй вопрос cluster模块имеет встроенную функцию балансировки нагрузки. master进程отвечает за прослушивание порта для получения запросов, а затем через алгоритм планирования назначает их соответствующим worker进程(по умолчанию). При циклическом переборе алгоритм планирования можно изменить с помощью переменной среды NODE_CLUSTER_SCHED_POLICY ).
Когда код генерирует исключение, которое не было перехвачено, процесс завершается. В это время Node.js предоставляет process.on('uncaughtException', handler) для его перехвата, но когда Когда рабочий процесс сталкивается с неперехваченным исключением, он уже находится в неопределенном состоянии. В это время мы должны позволить процессу завершиться корректно:
+---------+ +---------+
| Рабочий |
+---------+ +----+----+
| неперехваченноеисключение |
+----------------+ |
| | +---------+
<----------+ |
| +----+----+
| отключить | разветвить нового работника |
+------------------------> + ----------------------- -> |
| подожди... |
| выход |
+------------------------> |
|
умереть |
|
| | Когда в процессе возникает исключение, вызывающее сбой или OOM, которое уничтожается системой, в отличие от случая, когда происходит неперехваченное исключение, у нас все еще есть шанс позволить процессу продолжить выполнение. текущий процесс завершается напрямую, и Мастер немедленно создает нового работника.
Модуль child_process предоставляет возможность создавать дочерние процессы, что представляет собой просто执行cmd命令的能力. По умолчанию stdin、 stdout 和stderr 的管道会在父Node.js 进程和衍生的子进程之间建立. Эти конвейеры имеют ограниченную (и зависящую от платформы) пропускную способность. Если дочерний процесс превышает этот предел при записи в стандартный вывод и выходные данные не захватываются, дочерний процесс блокируется и ждет, пока буфер канала примет дополнительные данные. Это то же самое поведение, что и труба в оболочке. Если выходные данные не используются, используйте параметр { stdio: 'ignore' }.
const cp = require('child_process'); Дочерний процесс, созданный через API, не имеет необходимой связи с родительским процессом,
для создания дочерних процессов используются 4 асинхронных метода: fork, exec, execFile, spawn
Node.
fork(modulePath, args) : используется, когда вы хотите запустить процесс Node как независимый процесс, чтобы обработка вычислений и дескриптор файла были отделены от основного процесса Node (копирование дочернего процесса).Non-Node
spawn(command, args)spawn(command, args) : обработка некоторых проблем. Используйте execFile(file, args[, callback]), когда имеется много операций ввода-вывода подпроцесса или когда процесс имеет большой объем выходных данныхexecFile(file, args[, callback]) используйте его, когда вам нужно выполнить только внешнюю программу. скорость выполнения высокая, и обработка ввода пользователя относительно безопасна.exec(command, options) : используется, когда вы хотите напрямую получить доступ к команде оболочки потока. Обязательно обратите внимание натри метода синхронизации, введенные пользователем: execSync . execFileSync , spawnSync

Остальные три метода являются расширениями spawn() .
. Помните, что производный дочерний процесс Node.js не зависит от. Родительский процесс, за исключением канала связи IPC, установленного между ними. Каждый процесс имеет свою собственную память и свой экземпляр V8
.
Например, создайте два файла, worker.js и master.js, в каталоге:
# child.js.
const t = JSON.parse(process.argv[2]);
console.error(`дочерний процесс t=${JSON.stringify(t)}`);
process.send({hello:`son pid=${process.pid}, пожалуйста, передайте папе процесс pid=${process.ppid} hello`});
process.on('сообщение', (msg)=>{
console.error(`дочерний процесс msg=${JSON.stringify(msg)}`);
}); # родитель.js
const {fork} = require('child_process');
for(пусть я = 0; я <3; я++){
const p = fork('./child.js', [JSON.stringify({id:1,name:1})]);
p.on('сообщение', (msg) => {
console.log(`messsgae from child msg=${JSON.stringify(msg)}`, );
});
p.send({hello:`Привет от папы ${process.pid} id процесса=${i}`});
} 
Запустите родительский.js через node parent.js , а затем проверьте количество процессов через ps aux | grep worker.js Мы можем обнаружить, что в идеале количество процессов равно количеству ядер ЦП, и каждый процесс использует одно. Ядро процессора.
Это классический режим Master-Worker (режим master-slave).

На самом деле разветвление процесса обходится дорого, а цель копирования процесса — полностью использовать ресурсы ЦП, поэтому NodeJS использует событийно-ориентированный подход в одном потоке для решения проблемы высокого параллелизма.
Применимые сценарии <br/> Обычно используются для сценариев, требующих много времени, и реализуются с использованием узла, например, загрузка файлов;
Fork может реализовать многопоточную загрузку: разделите файл на несколько блоков, затем каждый процесс загружает часть и, наконец, объединяет их вместе.
const cp = require('child_process');
// Первый параметр — это имя или путь к исполняемому файлу, который нужно запустить. вот эхо
cp.execFile('echo', ['привет', 'мир'], (err, stdout, stderr) => {
если (ошибка) { console.error(ошибка });
console.log('stdout: ', stdout);
console.log('stderr: ', stderr);
}); Применимые сценарии <br/> Больше подходит для задач с небольшими накладными расходами и большим вниманием к результатам, например, ls и т. д.
в основном используется для выполнения метода оболочки, а spawn - для него. по-прежнему вызывается внутри, но существует максимальный предел кэша.
const cp = require('child_process');
cp.exec(`cat ${__dirname}/messy.txt | sort | uniq`, (err, stdout, stderr) => {
console.log(stdout);
}); Применимые сценарии <br/>Более подходят для задач с небольшими накладными расходами и большим вниманием к результатам, например ls и т. д.;
одну задачу
const cp = require('child_process');
const child = cp.spawn('echo', ['привет', 'мир']);
child.on('ошибка', console.error);
# Вывод представляет собой поток, выводимый на стандартный вывод основного процесса, консоль child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr); Многозадачная конкатенация
const cp = require('child_process');
константный путь = требуется ('путь');
const cat = cp.spawn('cat', [path.resolve(__dirname, 'messy.txt')]);
const sort = cp.spawn('sort');
const uniq = cp.spawn('uniq');
#Вывод — поток cat.stdout.pipe(sort.stdin);
sort.stdout.pipe(uniq.stdin);
uniq.stdout.pipe(process.stdout); Применимые сценарии
;
Spawn является потоковым, поэтому он подходит для трудоемких задач, таких как выполнение установки npm и печать процесса установки
запускается после завершения процесса и стандартного потока ввода и вывода (sdtio) дочерний процесс был 'close' . Это событие отличается от exit , поскольку несколько процессов могут использовать один и тот же поток stdio.
Параметры:
Вопрос: Должен ли код существовать?
(Кажется, не из комментариев к коду) Например, если вы используете kill чтобы убить дочерний процесс, какой будет код?
параметры выхода:
код, сигнал, если дочерний процесс завершается сам по себе, то code является кодом выхода, в противном случае он равен нулю;
Если дочерний процесс завершается посредством сигнала, то signal является сигналом завершения процесса, в противном случае он равен нулю.
Из двух один не должен быть нулевым.
Что следует отметить :
Когда срабатывает событие exit , поток stdio дочернего процесса все еще может быть открыт. (Сценарий?) Кроме того, nodejs прослушивает сигналы SIGINT и SIGTERM. То есть, когда nodejs получает эти два сигнала, он не завершает работу немедленно. Вместо этого он сначала выполняет некоторую работу по очистке, а затем повторно выдает эти два сигнала. (Визуально в это время js может выполнять работу по очистке, например закрытие базы данных и т. д.)
SIGINT : прерывание, сигнал завершения программы, обычно выдаваемый, когда пользователь нажимает CTRL+C, используемый для уведомления приоритетного процесса о завершении процесса.
SIGTERM : завершение, сигнал завершения программы. Этот сигнал может быть заблокирован и обработан и обычно используется для нормального завершения программы. Команда оболочки kill генерирует этот сигнал по умолчанию. Если сигнал не может быть прекращен, мы попробуем SIGKILL (принудительное завершение).
При возникновении следующих событий возникает ошибка. При возникновении ошибки выход может сработать, а может и не сработать. (Сердце разбито)
запускается, когда для отправки сообщения используется process.send() .
параметр :
message — это объект json или примитивное значение; sendHandle , объект net.Socket или объект net.Server (студенты, знакомые с кластером, должны быть знакомы с этим)
: при вызове .disconnected() установите его. к ложному. Указывает, может ли он получать сообщения от дочернего процесса или отправлять сообщения дочернему процессу.
.disconnect() : закрывает канал IPC между родительским и дочерним процессами. При вызове этого метода срабатывает событие disconnect . Если дочерний процесс является экземпляром узла (созданным с помощью child_process.fork()), то внутри дочернего процесса также можно активно вызывать process.disconnect() для завершения канала IPC.
реагирует на однопоточные проблемы. Для имитации многопоточной обработки обычно используются многопоточные методы.
заняты процессом Node. Ядром 7-поточного
Node является движок v8. После запуска Node будет создан экземпляр v8. Этот экземпляр является
.单线程, но хост-среда Javascript, будь то Node или браузер, является многопоточной.
Почему Javascript однопоточный?
Эта проблема должна начинаться с браузера. Представьте, что для операций DOM в среде браузера несколько потоков работают с одним и тем же DOM, это означает, что операция DOM может выполняться только одним способом. избегать конфликтов рендеринга DOM. В среде браузера поток рендеринга пользовательского интерфейса и механизм выполнения JS являются взаимоисключающими. Когда один из них выполняется, другой будет приостановлен. Это определяется механизмом JS.
worker_threads.
const {.
isMainThread,
родительский порт,
рабочие данные,
идентификатор потока,
Канал сообщений,
Порт сообщений,
Рабочий
} = require('worker_threads');
функция mainThread() {
для (пусть я = 0; я <5; я++) {
const работник = новый работник (__filename, {workerData: я });
worker.on('exit', code => { console.log(`main: рабочий остановлен с кодом выхода ${code}`); });
worker.on('сообщение', сообщение => {
console.log(`main: получить ${msg}`);
worker.postMessage(msg + 1);
});
}
}
функция workThread() {
console.log(`worker: workerDate ${workerData}`);
родительскийПорт.он('сообщение', сообщение => {
console.log(`работник: получить ${msg}`);
}),
родительскийПорт.postMessage(workerData);
}
если (isMainThread) {
основной поток();
} еще {
рабочийПоток();
} const Assert = require('assert');
константа {
Рабочий,
Канал сообщений,
Порт сообщений,
isMainThread,
родительский порт
} = require('worker_threads');
если (isMainThread) {
const работник = новый работник (__filename);
const subChannel = новый MessageChannel ();
worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
subChannel.port2.on('сообщение', (значение) => {
console.log('получено:', значение);
});
} еще {
родительскийПорт.once('сообщение', (значение) => {
Assert(value.hereIsYourPort экземпляр MessagePort);
value.hereIsYourPort.postMessage('рабочий отправляет это');
значение.здесьВашПорт.закрыть();
});
}Процесс — это наименьшая единица распределения ресурсов, а поток — наименьшая единица планирования ЦП.
IPC (Inter-process communication) —进程间通信. Поскольку каждый процесс после создания имеет собственное независимое адресное пространство, целью реализации IPC является разделение доступа к ресурсам между процессами.
Существует множество способов реализации IPC: каналы, очереди сообщений, семафоры, доменные сокеты и Node.js реализуется через каналы.

Фактически, родительский процесс сначала создаст канал IPC и прослушает этот IPC, прежде чем создавать дочерний процесс, а затем создаст дочерний процесс. Он сообщит дочернему процессу и файловому дескриптору, связанному с каналом IPC, через переменную среды (). NODE_CHANNEL_FD). Запускается дочерний процесс. В это время канал IPC подключается в соответствии с файловым дескриптором для установления соединения с родительским процессом.

Дескриптор — это ссылка, которую можно использовать для идентификации ресурса. Он содержит дескриптор файлового ресурса, указывающий на объект.
Обычно, когда мы хотим отслеживать несколько процессов на одном порту, мы можем рассмотреть возможность использования основного агента процесса:

Однако это решение с прокси-сервером приведет к тому, что каждый прием запроса и пересылка прокси-сервера будут использовать два файловых дескриптора, а файловые дескрипторы системы будут ограничены. Этот подход повлияет на масштабируемость системы.
Итак, зачем использовать ручки? Причина в том, что в реальных сценариях приложения установление связи IPC может включать более сложные сценарии обработки данных. Дескриптор может быть передан в качестве второго необязательного параметра метода send() , что означает, что идентификатор ресурса IPC может быть передан напрямую. передача позволяет избежать использования файловых дескрипторов, вызванных пересылкой через прокси, упомянутой выше.

Ниже приведены типы дескрипторов, которые поддерживают отправку:
После того, как родительский процесс потерянного процесса создает дочерний процесс, родительский процесс завершается, но один или несколько дочерних процессов Процессы, соответствующие родительскому процессу, все еще живы. Это иллюстрируется следующим примером кода.
# Worker.js
const http = require ('http');
const server = http.createServer((req, res) => {
res.end ('Я работаю, pid:' + process.pid + ', ppid:' + process.ppid);
// Записать текущий PID PID -PID и PID PID PID PID
});
пусть работник;
process.on ('message', function (сообщение, sendhandle) {
if (message === 'server') {
Рабочий = Sendhandle;
Worker.on ('connection', function (socket) {
Server.emit ('Connection', Socket);
});
}
}) ;
const fork = require ('child_process'). fork;
const server = require ('net'). createServer ();
Server.Listen (3000);
const ripemer = fork ('corker.js');
Worker.send ('Server', Server);
console.log ('Созданный работник, PID: %s PPID: %s', работник. PID, Process.pid);
process.exit (0);
// После создания дочернего процесса основной процесс выходит .

Поскольку родительский процесс выходит в Master.js, монитор активности показывает только рабочую процесс.

Убедитесь еще раз, откройте интерфейс Console Call, вы можете увидеть, что PPID, соответствующий работнику 5611, составляет 1 (для процесса инициирования), и в настоящее время он стал сиротой.

Процесс Daemon работает на заднем плане и не влияет на терминал.
Студенты, которые разрабатывают Node.js, node app.js быть знакомы с ним.前台运行模式.
Если используется метод процесса Daemon, после того, как я выполняю node app.js , чтобы запустить процесс обслуживания в этом терминале, я также могу делать другие вещи на этом терминале, не затрагивая друг друга.
.
options.detached
const spawn = require ('child_process'). Spawn;
функция startDaemon () {
const daemon = spawn ('node', ['daemon.js'], {
CWD: '/usr',
Отдельно: правда,
stdio: «Игнорировать»,
});
console.log ('Daemon Process начинает родительский процесс PID: %S, Daemon Process Pid: %s', Process.pid, Daemon.pid);
daemon.unref ();
}
startDaemon
()
Логика обработки в файле daemon.js запускает таймер и выполняет его каждые 10 секунд, чтобы этот ресурс не вышел.
Детского процесса.
const fs = require('fs');
const {console} = require ('Консоль');
// пользовательский простой регистратор
const logger = new Console (fs.createwritestream ('./ stdout.log'), fs.createwritestream ('./ stderr.log'));
setInterval (function () {
logger.log ('daemon pid:', process.pid, ', ppid:', process.ppid);
}, 1000
*
10);


В реальной работе мы не являемся незнакомцами для процессов демон, таких как PM2, кластер яиц и т. Д. Вышеупомянутое-просто простой демонстрация для объяснения процесса демона. Процесс демона все еще очень высокий.
5.Каков
текущийprocess.cwd()
Из каталога родительского процесса, который может быть получен через process.chdir()
Что
это делает?
Правильный результат не будет получен. В другом случае сторонний модуль, упомянутый в программе, также искал на основе каталога, в котором начинается текущий процесс.
// Пример Process.chdir ('/users/may/documents/test/') // Установите текущую консоль каталога процессов.