为什么 Node cluster.fork() 在作为模块实现时会分叉父作用域

LPG*_*LPG 7 mocha.js node.js

我正在尝试实现一个使用cluster. 问题是整个父作用域与预期的集群代码一起分叉。我在用 Mocha 为模块编写测试时发现了这一点:测试套件将运行多次,而不是一次。

见下文,myModule.js 创建 N 个 worker,每个 CPU 一个。这些工作人员是 http 服务器,也可以是其他任何东西。

每次 test.js 运行时,脚本都会运行 N + 1 次。在下面的示例中,console.log 在我的四核上运行了 5 次。

有人可以解释这是一个实现问题还是集群配置问题?有什么方法可以限制 fork() 的范围而不必导入模块(如本解决方案 https://github.com/mochajs/mocha/issues/826)?

/// myModule.js ////////////////////////////////////

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

var startCluster = function(){

  if (cluster.isMaster) {
    // CREATE A CLUSTER OF FORKED WORKERS, ONE PER CPU
    //master does not listen to UDP messages.

    for (var i = 0; i < numCPUs; i++) {

      var worker = cluster.fork();
    }


  } else {
    // Worker processes have an http server.
    http.Server(function (req, res){
      res.writeHead(200);
      res.end('hello world\n');
    }).listen(8000);

  }

  return
}

module.exports = startCluster;

/////////////////////////////////////////////////

//// test.js ////////////////////////////////////

var startCluster = require('./myModule.js')

startCluster()

console.log('hello');

////////////////////////////////////////////////////////
Run Code Online (Sandbox Code Playgroud)

LPG*_*LPG 7

所以我会冒险回答。仔细查看节点文档,有一个cluster.setupMaster可以覆盖默认值。a 上的默认值cluster.fork()是执行当前脚本,带有“工作文件的文件路径。(默认值=process.argv[1])” https://nodejs.org/docs/latest/api/cluster.html#cluster_cluster_settings

因此,如果另一个模块使用 cluster.fork() 调用导入脚本,它仍将使用 process.argv[1] 的路径,这可能不是您期望的路径,并且会产生意想不到的后果。

所以我们不应该像官方文档建议的那样在同一个文件中初始化集群 master 和 worker。将 worker 分离到一个新文件并覆盖默认设置是明智的。(同样为了安全起见,您可以使用 __dirname 添加目录路径)。

cluster.setupMaster({ exec: __dirname + '/worker.js',});

所以这里是更正的实现:

/// myModule.js ////////////////////////////////////

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

var startCluster = function(){
  cluster.setupMaster({ 
    exec: __dirname + '/worker.js'
  });

  if (cluster.isMaster) {
    // CREATE A CLUSTER OF FORKED WORKERS, ONE PER CPU    
    for (var i = 0; i < numCPUs; i++) {
       var worker = cluster.fork();
    }

  } 
  return
}

module.exports = startCluster;

/////////////////////////////////////////////////

//// worker.js ////////////////////////////////////
var http = require('http');

// All worker processes have an http server.
http.Server(function (req, res){
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);

////////////////////////////////////////////////////////

//// test.js ////////////////////////////////////

var startCluster = require('./myModule.js')

startCluster()

console.log('hello');

////////////////////////////////////////////////////////
Run Code Online (Sandbox Code Playgroud)

你应该只看到 'hello' 一次而不是 1 * Number of CPUs