參考
Node.js 是以單線程的模式運行的,但它使用的是事件驅動來處理併發,這樣有助於我們在多核 cpu 的系統上創建多個子進程,從而提高性能。
每個子進程總是帶有三個流對象:child.stdin
, child.stdout
和child.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);
});
}