Node.js 集群 - 为什么脚本没有明显原因运行多次?

问题描述

所以我将下面的代码写入了一个 MyScript.js 文件; (直接取自 https://nodejs.org/api/cluster.html 处的 node.js 文档)

const cluster = require('cluster');
const http = require('http');
const numcpus = require('os').cpus().length;

console.log("I'm at the top"); //PAY ATTENTION TO THIS LINE

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numcpus; i++) {
    cluster.fork();
  }

  cluster.on('exit',(worker,code,signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req,res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

当我运行它时

>node MyScript.js

,它在命令提示符下输出以下内容

I'm at the top...
Master 24632 is running
I'm at the top...
Worker 25536 started
I'm at the top...
Worker 17524 started
I'm at the top...
Worker 19020 started
I'm at the top...
Worker 11352 started

它如何同时运行 IF 部分和 ELSE 部分?导致 MyScript.js 多次运行的魔力在哪里?!

更新:tl;dr; 从那以后我得出的真正答案是“魔法”发生是因为 cluster.fork() 实际上说:创建一个新环境 (V8) 来执行“一些 javascript 模块”,如 process.argv[1] 所定义;这恰好是 MyScript.js 的完整路径;

解决方法

将集群视为分叉进程,当您执行 for 迭代时,您将创建多个将运行相同脚本的子进程(fork 部分),但是当它们检查 {{ 1}} 语句,他们将执行 if 部分,因为集群的主节点(只有一个)创建了现在正在检查 else 的进程。

运行的进程数与您计算机上的 CPU 数相同,因此,例如,如果您的 CPU 有 8 个内核,则您希望有 8 个工作线程在运行。

所以基本上,你希望只运行一次以下

if

但多次出现以下情况(与您计算机中的 CPU 数量一样多,因为您以这种方式对其进行了配置)

console.log(`Master ${process.pid} is running`);

// Fork workers.
for (let i = 0; i < numCPUs; i++) {
  cluster.fork();
}

cluster.on('exit',(worker,code,signal) => {
  console.log(`worker ${worker.process.pid} died`);
});

然后,当子进程(不是主进程)完成时,您将看到以下 // Workers can share any TCP connection // In this case it is an HTTP server http.createServer((req,res) => { res.writeHead(200); res.end('hello world\n'); }).listen(8000); console.log(`Worker ${process.pid} started`);

console.log

编辑:

那么为什么它会多次运行 console.log(`worker ${worker.process.pid} died`); ? Node 所做的(与 C 不同)是,当它执行 console.log("I'm at the top"); 时,它会创建 V8 引擎的一个新实例,并且每次创建新进程时都会完全执行代码。 函数名称 fork 具有误导性,因为它不会复制您的进程并从您所在的位置开始运行,而是生成一个新进程,使该进程再次运行整个脚本。