nodejs多进程exec/spanw/fork

参考
Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能。

每个子进程总是带有三个流对象:child.stdin, child.stdoutchild.stderr

exec

  • exec - child_process.exec 使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式一次性返回。
  • exec方法会从子进程中返回一个完整的buffer。
  • 默认情况下,这个buffer的大小应该是200k。如果子进程返回的数据大小超过了200k,程序将会崩溃,同时显示错误信息Error:maxBuffer exceeded
  • 你可以通过在exec的可选项中设置一个更大的buffer体积来解决这个问题,但是你不应该这样做,因为exec本来就不是用来返回很多数据的方法。
require('child_process').exec('dir', {encoding: ‘utf-8}, function(err, stdout, stderr) {
    if (err) {
        console.log(error.stack);
        console.log('Error code: ' + error.code);
        console.log('Signal received: ' + error.signal);
    }
    //console.log(err, stdout, stderr);
    console.log('data : ' + stdout);
}).on('exit', function (code) {
    console.log('子进程已退出, 退出码 ' + code);
});

例子

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 workerProcess = child_process.exec('node support.js '+i, function (error, stdout, stderr) {
        if (error) {
            console.log(error.stack);
            console.log('Error code: '+error.code);
            console.log('Signal received: '+error.signal);
        }
        // 子进程执行完备和'exit'的回调函数执行完毕后,输出子进程的stdout和stderr
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
    });
 
    workerProcess.on('exit', function (code) {
    	// 子进程执行完毕,后执行该回调函数
        console.log('子进程已退出,退出码 '+code);
    });
}

spawn

  • spawn - child_process.spawn 使用指定的命令行参数创建新进程。spawn 会返回一个带有stdout和stderr流的对象。
  • 你可以通过stdout流来读取子进程返回给Node.js的数据。
  • stdout拥有data,end以及一般流所具有的事件。
  • 当你想要子进程返回大量数据给Node时,比如说图像处理,读取二进制数据等等,你最好使用spawn方法。
var child_process = require('child_process');
var spawnObj = child_process.spawn('ping', ['127.0.0.1'], {encoding: 'utf-8'});
spawnObj.stdout.on('data', function(chunk) {
	// 流的形式读入
	// 如64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.029 ms
    console.log(chunk.toString());
});

spawnObj.stderr.on('err', function(err) {
    console.log(err);
});

spawnObj.on('exit', function(code) {
    console.log('子进程已退出, 退出码 ' + code);
});
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.029 ms

64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.058 ms

64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.057 ms

64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.059 ms

64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.058 ms

64 bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.059 ms

64 bytes from 127.0.0.1: icmp_seq=7 ttl=64 time=0.058 ms

64 bytes from 127.0.0.1: icmp_seq=8 ttl=64 time=0.058 ms

^C

例子

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 workerProcess = child_process.spawn('node', ['support.js', i]);
   // exec在'close'在把stdout统一处理
   // spawn不同于exec
   // spawn受到流后立刻处理收到的stdout,结束再调用'close'
   workerProcess.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
   });
 
   workerProcess.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
   });
 
   workerProcess.on('close', function (code) {
      console.log('子进程已退出,退出码 '+code);
   });
}

fork

  • fork - child_process.fork 是 spawn()的特殊形式,用于在子进程中运行的模块,如 fork(‘./son.js’) 相当于 spawn(‘node’, [‘./son.js’]) 。
  • 与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信。
  • fork生成的child_process有独有的send方法,通过pid通信,可用于父子进程通信
  • send 发送 sendHandle 时实际上不是(也不能)直接发送 JavaScript 对象,而是发送文件描述符(最终以 JSON 字符串发送),其他进程能够通过这个文件描述符还原出对应对象。
  • send方法是同步的因此不建议发送大量数据, 发送大量的数据可以使用 pipe 来代替

parent.js

console.log('parent pid: ' + process.pid);
var fork = require('child_process').fork;
//fork方法返回的是子进程
var child = fork('./child.js');
// child.pid得到子进程pid
console.log('fork return pid: ' + child.pid);
// 接收消息
child.on('message', function(msg){
    console.log('parent get message: ' + JSON.stringify(msg));
});
// 给子进程发送消息
child.send({key: 'parent value'});

child.js

console.log('child pid: ' + process.pid);
// 接收消息
process.on('message', function(msg){
    console.log('child get message: ' + JSON.stringify(msg));
});
// 给父进程发送消息
process.send({key: 'child value'});

例子

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);
   });
}
发布了290 篇原创文章 · 获赞 114 · 访问量 61万+

猜你喜欢

转载自blog.csdn.net/jason_cuijiahui/article/details/104189158
今日推荐