问题描述
我正在尝试实现使用cluster
的Node模块.问题是整个父作用域与预期的群集代码一起被分叉.我在Mocha中为模块编写测试时发现了它:测试套件将运行多次,而不是一次.
I'm attempting to implement a Node module which uses cluster
. The problem is that the entire parent scope is forked alongside the intended cluster code. I discovered it while writing tests in Mocha for the module: the test suite will run many times, instead of once.
参见下文,myModule.js创建N个工作线程,每个CPU一个.这些工作程序是http服务器,或者可以是其他任何服务器.
See below, myModule.js creates N workers, one for each CPU. These workers are http servers, or could be anything else.
每次运行test.js时,脚本将运行N +1次.在下面的示例中,console.log在我的四核上运行5次.
Each time the test.js runs, the script runs N + 1 times. In the example below, console.log runs 5 times on my quad core.
有人可以解释这是实现问题还是集群配置问题?有什么方法可以限制fork()的范围而不必导入模块(如此解决方案中的 https://github.com/mochajs/mocha/issues/826 )?
Can someone explain if this is an implementation issue or cluster config issue? Is there any way to limit the scope of fork() without having to import a module ( as in this solution 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');
////////////////////////////////////////////////////////
推荐答案
所以我冒险回答.仔细查看节点文档,有一个cluster.setupMaster
可以覆盖默认值. cluster.fork()
上的默认值是执行当前脚本,并带有工作文件的文件路径.(默认值= process.argv [1])" https://nodejs.org/docs/latest/api/cluster.html#cluster_cluster_settings
So I'll venture an answer. Looking closer at the node docs there is a cluster.setupMaster
which can override defaults. The default on a cluster.fork()
is to execute the current script, with "file path to worker file. (Default=process.argv[1])"https://nodejs.org/docs/latest/api/cluster.html#cluster_cluster_settings
因此,如果另一个模块正在通过cluster.fork()调用导入脚本,则它将仍然使用process.argv [1]的路径,该路径可能不是您期望的路径,并且会产生意想不到的后果.
So if another module is importing a script with a cluster.fork() call, it will still use the path of process.argv[1], which may not be the path you expect, and have unintended consequences.
因此,我们不应该在官方文档中建议的同一文件中初始化集群主服务器和辅助服务器.谨慎的做法是将worker分成一个新文件并覆盖默认设置. (为了安全起见,您可以使用__dirname添加目录路径.)
So we shouldn't initialize the cluster master and worker in the same file as the official docs suggest. It would be prudent to separate the worker into a new file and override the default settings. (Also for safety you can add the directory path with __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');
////////////////////////////////////////////////////////
您只能看到一次"hello",而不是1 * CPU数量
You should only see 'hello' once instead of 1 * Number of CPUs
这篇关于为什么Node cluster.fork()在实现为模块时会派生父作用域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!