nodejs笔记4--多进程架构简介

填坑: 1 nodejs笔记1--异步API与其局限性 2 nodejs笔记2--nodejs中的事件通知机制

填坑:

1. nodejs笔记1--异步API与其局限性

2. nodejs笔记2--nodejs中的事件通知机制

3. nodejs笔记3--事件通知机制的两个应用场景

4. nodejs笔记4--多进程架构

应用场景

操作系统的资源是有限的,这通常意味者操作系统分配给进程或线程的资源是有限的,在多核cpu普及的时代,如果只使用单核(常说node是单线程的),则无法充分压榨硬件性能.

模块介绍

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, <directory>', 'triggers path', DEFAULT_TRG_PATH)

.action(function(opts) {

start(opts);

});

program.command('create')

.description('start create')

.option('-d, --directory, <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.js

console.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, <file>', '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有什么区别?

未登录用户
全部评论0
到底啦