首页 > 代码库 > Nodejs学习之多进程架构

Nodejs学习之多进程架构

操作系统的资源是有限的,这通常意味者操作系统分配给进程或线程的资源是有限的,在多核cpu普及的时代,如果只使用单核(常说node是单线程的),则无法充分压榨硬件性能,今天和大家介绍的就是nodejs多进程架构,希望可以帮助大家更好的学习nodejs ,一起来看看吧。 
模块介绍 
node提供了child_process模块,该模块提供4个方法 
1.spawn() 启动一子进程来执行命令 
2.exec() 启动一子进程来执行命令,与spawn()不同的是提供一个回调函数获知子进程的状况 
3.execFile() 启动一个子进程来执行可执行文件 
4.fork() 与spawn()类似,指定执行的javascript文件模块即可 
惯用做法 
通常,node项目会有个bin目录,里面的文件类似于应用程序入口,结合 commander 包实现根据命令行参数执行相应代码逻辑的功能: 
var child_process = require(’child_process’); var fs = require(’fs’); var os = require(’os’); var program = require(’commander’); 
const EventEmitter = require(’events’).EventEmitter; const ee = new EventEmitter(); 
var config = require(’../config.json’); var DEFAULT_TRG_PATH = config.triggersPath; 
program.command(’start’) 
.description(’start the application’) 
.option(’-d, --directory,’, ’triggers path’, DEFAULT_TRG_PATH) 
.action(function(opts) { 
start(opts); 
}); 
program.command(’create’) 
.description(’start create’) 
.option(’-d, --directory,’, ’triggers path’, DEFAULT_TRG_PATH) 
.action(function(opts) { 
create(opts); 
}); 
program.parse(process.argv); 
function start(opts){ 
console.log(1111); 
}function create(opts){ 
console.log(1111); 

假设需要执行 start 方式,仅需在命令行带上 start参数即可: 
node ./bin/www start 
同理,其他方法可以通过该方式按需调用. 都不到为啥会扯到commander包的使用,可能是通常情况下想使用多进程架构时功能已经足够复杂,而首先想到的就是用commander包使程序看上去比较好看吧-_- 
好了,言归正传,其实我就想使用线程池这种所谓的高级语言封装好的方法而已,可惜node并没有这种. 
很多文章都说过,API的用法,这里只简单说说他们之间的区别. 
spawn 
spawn会返回一个代后stdout与stderr流的对象,可以通过stdout流来读取子进程返回给主进程的数据.如果子进程需要返回大量数据,则应该使用spawn而不是exec. 注意,stdout是以buffer格式返回,相对于exec而言,buffer数据可以很大,也就是说如果主进程需要接收子进程大量的数据时,应该选择spawn来实现: 
var absScript = path.resolve(process.cwd()+’/lib/’, ’child.js’); var child = child_process.spawn(process.argv[0],[absScript,’create’,’--path=’ + dConfig.triggersPath + trgFile]); 
child.stdout.on(’data’, function(data){ 
console.log(`${data}`); 
}); 
child.stdout.on(’end’, function(){ 
console.log(’end’); 
}); 
child.on(’error’, function(err){ 
console.log(’Failed to start child process.’); 
}); 
child.on(’close’,function(code){ 
console.log(’closecode:’+ code); 
}); 
//child.jsconsole.log(’modelhunter.js’); var fs = require(’fs’); var program = require(’commander’); var trgs = require(’./components/trgs’); var ModelHunter = module.exports = {}; 
program.command(’create’) 
.description(’create’) 
.option(’-p, --path,’, ’triggers path’, ’’) 
.action(function(opts) { 
if(opts.path.length>0){ 
console.log(opts.path); 
setTimeout(function(){ 
console.log(’aaaaaaa’); 
process.exit(0); 
},1000); 

}); 
program.parse(process.argv); 
最终输出为 
modelhunter.js D:/xxxxx.xx 
aaaaaaa 
end closecode:0 
exec 与 execFile 
exec相当于spawn,通讯的内容有限制.适合执行复杂的shell命,与主进程的通讯是一次性的,子进程的结果只能返回一次. 
execFile跟exec类型,执行一个文件,或脚本或可执行文件等 
exec做了相当的封装,主要用于执行复杂的shell命令. 
fork 
fork使用同样的进程复制自身的环境执行脚本,但只能执行node脚本,fork可以很方便的与主进程进行通讯: 
//注意这里第一个参数即是目标脚本的路径.var absScript = path.resolve(process.cwd()+’/lib/’, ’modelhunter.js’); var child = child_process.fork(absScript,[’create’,’--path=’ + dConfig.triggersPath + trgFile]); 
child.on(’message’,function(m){ 
console.log(’message:’+ m); //接收子进程消息 
}); 
child.on(’close’,function(code){ 
console.log(code); 
}); 
child.send(’null’); //向子进程发送消息 
//child.js 
process.on(’message’,function(m){ 
console.log(’chilid Listen:’, m); //接收主进程消息 
}); 
process.send(’this childprocess’); //向主进程发送消息 
总结 
如果想使用多进程架构,按需选择相应的API.即可实现类似"进程池"的功能,当然,可能要配合事件通知机制. 
这里提出几点疑问: 
1.如果是一个网站的服务端,为了充分利用CPU资源,通常会使用多进程架构,但是我们应该选择fork还是spawn呢? 
2.pm2的fork mode 与 cluster mode有什么区别? 

文章来源:繁星UED 

Nodejs学习之多进程架构