Node.js 多进程
参考https://www.runoob.com/nodejs/nodejs-process.html
- Node.js是单线程的模式运行的,但是使用事件驱动型来处理并发,所以在多核CPU上创建多个子进程来提高性能;
- 每个子进程带三个流对象:child.stdin、child.stdout、child.stderr。
- 子进程的三个对象可能会共享父进程的stdio流,或是共享独立的被导流的流对象。
Node.js提供了child_process模块来创建子进程:
- child_process.exec():使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回;
- child_process.spawn():使用指定的命令行参数创建子进程;
- child_process.fork():是child_process.spawn()的特殊形式,使用子进程运行脚本或命令。
如fork('./son.js')相当于spawn('node', ['./son.js'])。与spawn方法不同的是,fork会在父子进程之间建立一个通信管道,用于进程之间的通信。
exec()方法
使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回。
语法
child_process.exec(command[, options], callback)
- command:字符串,将要运行的命令,参数以空格隔开;
- options:对象,可以是:
- cwd,字符串,子进程的当前工作目录(Current Working Directory);
- env,对象,环境变量键值对(Environment key-value)
- encoding,字符串,字符编码(默认'utf8')
- shell,字符串,将要执行的命令的shell(Linux中默认为bash shell,Windows中默认为cmd);
- timeout,数字,超时时间(默认为0,立即执行);
- maxBuffer,数字,子进程中允许存在的最大缓冲,超出此值子进程将被杀死;
- killSignal,字符串,结束信号(默认'SIGTERM');
- uid,数字,设置用户进程的ID;
- gid,数字,设置进程组的ID。
- callback:回调函数,包含三个参数err, stdout和stderr;
返回值
exec()方法返回最大的缓冲区的内容,并等待进程结束,一次性返回缓冲区的内容。
创建两个文件support.js和master.js:
support.js:
console.log("进程 "+process.argv[2]+"执行");
master.js:
const fs = require('fs');
const child_process = require('child_process');
for(let i=0;i<3;i++){
let workerProcess = child_process.exec('node support.js '+i, (err, stdout, stderr)=>{
if(err){
console.log(err.stack);
console.log('Error code: '+err.code);
console.log('Signal received: '+err.signal);
}
console.log('stdout: '+stdout);
console.log('stderr: '+stderr);
});
workerProcess.on('exit', (code)=>{
console.log('子进程已退出,退出码:'+code);
});
}
执行master.js,结果:
spawn()方法
child_process.spawn()使用指定的命令行参数来创建子进程。
语法
child_process.spawn(command[, args][, options])
- command:字符串,将要运行的命令;
- args:字符串参数数组,['arg1', 'arg2', ...]
- options:对象,可以是:
- cwd,字符串,子进程的当前工作目录(Current Working Directory);
- env,对象,环境变量键值对(Environment key-value);
- stdio,字符串数组,子进程的stdio配置;
- detached,布尔,是否子进程作为进程组的领导;
- uid,数字,设置用户进程的ID;
- gid,数字,设置进程组的ID。
返回值
spawn()方法返回ChildProcess对象,在进程返回大量数据时使用。进程一旦开始执行时,spawn()就开始接收响应。
还是master.js和support.js,
support.js:
console.log("进程 "+process.argv[2]+"执行");
master.js:
const fs = require('fs');
const child_process = require('child_process');
for(let i=0;i<3;i++){
//此处i可能会被转为string类型
let workerProcess = child_process.spawn('node', ['support.js', i]);
workerProcess.stdout.on('data', (data)=>{
console.log('stdout: '+data);
});
workerProcess.stderr.on('data', (data)=>{
console.log('stderr: '+data);
});
workerProcess.on('close', (code)=>{
console.log('子进程已退出,退出码:'+code);
});
}
结果:
fork()方法
child.process.fork()时spawn()方法的特殊形式,用于创建进程。与spawn方法不同的是,fork会在父子进程之间建立一个通信管道,用于进程之间的通信。
语法
child_process.fork(modulePath[, args][, options])
- modulePath:字符串,将要在子进程中运行的脚本;
- args:字符串数组,参数;
- options**:对象,可以是:
- cwd,字符串,子进程的当前工作目录(Current Working Directory);
- env,对象,环境变量键值对(Environment key-value);
- execPath,字符串,用于创建子进程的可执行文件;
- execArgv,字符串数组,execPath的参数;
- silent,布尔,是否将子进程的三个流对象关联至父进程,否则从父进程中继承(默认为false);
- uid,数字,设置用户进程的ID;
- gid,数字,设置进程组的ID
返回值
返回ChildProcess对象 ,比spawn()方法返回的实例还多一个内建的通信通道。
support.js:
console.log("进程 " + process.argv[2] + " 执行。" );
master.js:
const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
var worker_process = child_process.fork("support.js", [i]);
worker_process.on('close', function (code) {
console.log('子进程已退出,退出码 ' + code);
});
}
结果: