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

时间:2016-09-21 21:19:16

标签: node.js mocha

我正在尝试实现一个使用cluster的Node模块。问题是整个父作用域与预期的集群代码一起分叉。我在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');

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

3 个答案:

答案 0 :(得分:4)

所以我会冒险回答。仔细观察节点文档,有cluster.setupMaster可以覆盖默认值。 cluster.fork()上的默认值是执行当前脚本,其中包含&#34;工作文件的文件路径。 (缺省值= process.argv [1])&#34; https://nodejs.org/docs/latest/api/cluster.html#cluster_cluster_settings

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

因此,我们不应该在官方文档建议的同一文件中初始化群集主服务器和工作服务器。将工作者分成新文件并覆盖默认设置是明智的。 (为了安全起见,您可以使用__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');

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

你应该只看到&#39;你好&#39;一次而不是1 * CPU数量

答案 1 :(得分:1)

你需要拥有&#34; isMaster&#34;代码顶部的东西,而不是函数内部的东西。工作者将从模块的顶部运行(它不像C ++ fork,工作者从fork()点开始)。

答案 2 :(得分:0)

我假设你想让startCluster = require('。/ cluster-bug.js')只进行一次eval?好吧,那就是因为你的整个脚本都是集群的。你在startCluster中指定的只是让它在主集群和从集群之间变化。 cluster会生成初始化文件的fork文件。