新聞中心
node.js是基于單線程模型架構的,它能夠擁有高效的CPU利用率,卻限制了多個核心CPU的使用,為此,Node.js提供了child_process 模塊以通過多線程來實現對多核CPU的使用。

創(chuàng)新互聯建站是一家專業(yè)提供長治企業(yè)網站建設,專注與網站設計、成都做網站、H5技術、小程序制作等業(yè)務。10年已為長治眾多企業(yè)、政府機構等服務。創(chuàng)新互聯專業(yè)網站建設公司優(yōu)惠進行中。
穩(wěn)定性: 3 - 穩(wěn)定Node通過child_process模塊提供了popen(3)數據流。
它能在非阻塞的方式中,通過stdin,stdout和stderr傳遞數據。
請注意:某些程序使用內部線性緩沖I/O, 它并不妨礙node.js,只是你發(fā)送給子進程的數據不會被立即取消。
你可以使用require('child_process').spawn()或require('child_process').fork()創(chuàng)建一個子進程。這兩種方法有區(qū)別,在下文中將進行解釋。
開發(fā)過程中查看synchronous counterparts效率會更高。
類: ChildProcess
ChildProcess是一個EventEmitter。
子進程有三個相關的流child.stdin,child.stdout和child.stderr。他們可能和會父進程的stdiostreams共享,也可作為獨立的對象。
不能直接調用ChildProcess類,使用spawn(),exec(),execFile()或fork()方法來創(chuàng)建子進程的實例。
事件: 'error'
err{Error Object}錯誤。
發(fā)生于:
- 無法創(chuàng)建進程。
- 無法殺死進程。
- 無論什么原因導致給子進程發(fā)送消息失敗。
注意:exit事件有可能在錯誤發(fā)生后調用,也可能不調用,所以如果你監(jiān)聽這兩個事件來觸發(fā)函數,記得預防函數會被調用2次。
參考ChildProcess#kill()和ChildProcess#send()。
事件: 'exit'
code{Number} 退出代碼, 正常退出時才有效。signal{String} 如果是被父進程殺死,則它為傳遞給子進程的信號
子進程結束的時候觸發(fā)這個事件。如果子進程正常終止,則code為最終的退出代碼,否則為null。如果是由signal引起的終止,則signal為字符串,否則為 null。
注意:子進程的stdio流可能仍為開啟模式。
注意,node為'SIGINT'和'SIGTERM' 建立句柄,所以當信號來臨的時候,他們不會終止而是退出。
參靠waitpid(2)。
事件: 'close'
code{Number} 退出代碼, 正常退出時才有效。signal{String} 如果是被父進程殺死,則它為傳遞給子進程的信號。
子進程里所有stdio流都關閉時觸發(fā)這個事件。要和'exit'區(qū)分開,因為多進程可以共享一個stdio流。
Event: 'disconnect'
父進程或子進程中調用.disconnect()方法后觸發(fā)這個事件。斷開后不會在互發(fā)消息,并且.connected屬性值為false。
Event: 'message'
message{Object} 一個解析過的JSON對象,或者一個原始值。sendHandle{Handle object} 一個Socket或Server對象
通過.send(message, [sendHandle])傳遞消息。
child.stdin
- {Stream object}
子進程的stdin是Writable Stream(可寫流)。如果子進程在等待輸入,它就會暫停直到通過調用end()來關閉。
child.stdin是child.stdio[0]的縮寫。這兩個都指向同一個對象,或者null。
child.stdout
- {Stream object}
子進程的stdout是Readable Stream(可讀流)。
child.stdout是 child.stdio[1]的縮寫。 這兩個都指向同一個對象,或者null。
child.stderr
- {Stream object}
子進程的stderr是Readable Stream(可寫流)。
child.stderr是child.stdio[2]縮寫。這兩個都指向同一個對象,或者null。
child.stdio
- {Array}
子進程的管道數組和spawn的stdio里設置為'pipe' 的內容次序相對應。
注意,流[0-2]也能分別用ChildProcess.stdin、ChildProcess.stdout和ChildProcess.stderrNote來表示。
在下面的例子里,只有子進程的fd1設置為pipe管道,所以父進程的child.stdio[1]是流(stream),數組里其他值為null。
child = child_process.spawn("ls", {
stdio: [
0, // use parents stdin for child
'pipe', // pipe child's stdout to parent
fs.openSync("err.out", "w") // direct child's stderr to a file
]
});
assert.equal(child.stdio[0], null);
assert.equal(child.stdio[0], child.stdin);
assert(child.stdout);
assert.equal(child.stdio[1], child.stdout);
assert.equal(child.stdio[2], null);
assert.equal(child.stdio[2], child.stderr);child.pid
- {Integer}
子進程的PID。
例子:
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();child.connected
- {Boolean} 調用`.disconnect'后設置為false
如果.connected為 false,消息不再可用。
child.kill([signal])
signal{String}
發(fā)送信號給子進程。如果沒有參數,會發(fā)送'SIGTERM',參見signal(7)里的可用的信號列表。
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
grep.on('close', function (code, signal) {
console.log('child process terminated due to receipt of signal '+signal);
});
// send SIGHUP to process
grep.kill('SIGHUP');當信號無法傳遞的時候會觸發(fā)'error'事件。給已經終止的進程發(fā)送信號不會觸發(fā)'error'事件,但是可以能引起不可預知的后果: 因為有可能PID (進程ID) 已經重新分配給其他進程,信號就會被發(fā)送到新的進程里,無法想象這樣會引發(fā)什么樣的事情。
注意:當函數調用kill信號的時候,它實際并并不會殺死進程,只是發(fā)送信號給進程。
參見kill(2)
child.send(message[, sendHandle])
message{Object}sendHandle{Handle object}
使用child_process.fork()的時候,你能用child.send(message, [sendHandle])給子進程寫數據,子進程通過'message'接收消息。
例如:
var cp = require('child_process');
var n = cp.fork(__dirname + '/sub.js');
n.on('message', function(m) {
console.log('PARENT got message:', m);
});
n.send({ hello: 'world' });子進程的代碼'sub.js' :
process.on('message', function(m) {
console.log('CHILD got message:', m);
});
process.send({ foo: 'bar' });子進程代碼里的process對象擁有send()方法,當它通過信道接收到信息時會觸發(fā),并返回對象。
注意:父進程和子進程send()是同步的,不要用來發(fā)送大塊的數據(可以用管道來代替,參見child_process.spawn)。
不過發(fā)送{cmd: 'NODE_foo'}消息是特殊情況。所有包含NODE_前綴的消息都不會被觸發(fā),因為它們是node的內部的核心消息,它們會在internalMessage事件里觸發(fā),盡量避免使用這個特性。
child.send()里的sendHandle屬性用來發(fā)送TCP服務或socket對象給其他的進程,子進程會用接收到的對象作為message事件的第二個參數。
如果不能發(fā)出消息會觸發(fā)'error'事件,比如子進程已經退出。
例子: 發(fā)送 server 對象
以下是例子:
var child = require('child_process').fork('child.js');
// Open up the server object and send the handle.
var server = require('net').createServer();
server.on('connection', function (socket) {
socket.end('handled by parent');
});
server.listen(1337, function() {
child.send('server', server);
});子進程將會收到這個server對象:
process.on('message', function(m, server) {
if (m === 'server') {
server.on('connection', function (socket) {
socket.end('handled by child');
});
}
});注意,現在父子進程共享了server,某些連接會被父進程處理,某些會被子進程處理。
dgram服務器,工作流程是一樣的,監(jiān)聽的是message事件,而不是connection,使用server.bind而不是server.listen。(目前僅支持UNIX平臺)
例子: 發(fā)送 socket 對象
以下是發(fā)送socket對象的例子。他將會創(chuàng)建2個子線程,并且同時處理連接,一個將遠程地址74.125.127.100當做VIP發(fā)送到一個特殊的子進程,另外一個發(fā)送到正常進程。var normal=require('child_process').fork('child.js', ['normal']);var special = require('child_process').fork('child.js', ['special']);
// Open up the server and send sockets to child
var server = require('net').createServer();
server.on('connection', function (socket) {
// if this is a VIP
if (socket.remoteAddress === '74.125.127.100') {
special.send('socket', socket);
return;
}
// just the usual dudes
normal.send('socket', socket);
});
server.listen(1337);child.js代碼如下:
process.on('message', function(m, socket) {
if (m === 'socket') {
socket.end('You were handled as a ' + process.argv[2] + ' person');
}
});注意,當socket發(fā)送給子進程后,如果這個socket被銷毀,父進程不再跟蹤它,相應的.connections屬性會變?yōu)?code>null。這種情況下,不建議使用 .maxConnections。
child.disconnect()
關閉父子進程間的所有IPC通道,能讓子進程優(yōu)雅的退出。調用這個方法后,父子進程里的.connected標志會變?yōu)?code>false,之后不能再發(fā)送消息。
當進程里沒有消息需要處理的時候,會觸發(fā)'disconnect'事件。
注意,在子進程還有IPC通道的情況下(如fork()),也可以調用process.disconnect()來關閉它。
創(chuàng)建異步處理
這些方法遵從常用的異步處理模式(比如回調,或者返回一個事件處理)。
child_process.spawn(command[, args][, options])
command{String} 要運行的命令args{Array} 字符串參數表options{Object}cwd{String} 子進程的工作目錄env{Object} 環(huán)境stdio{Array|String} 子進程的stdio配置。customFds{Array} Deprecated 作為子進程stdio使用的文件標示符。detached{Boolean} 子進程將會變成一個進程組的領導者。uid{Number} 設置用戶進程的ID。(參見setuid(2))gid{Number} 設置進程組的ID。(參見 setgid(2))
- 返回: {ChildProcess object}
用指定的command發(fā)布一個子進程,args是命令行參數。如果忽略,args是空數組。
第三個參數用來指定附加設置,默認值:
{ cwd: undefined,
env: process.env
}創(chuàng)建的子進程里使用cwd指定工作目錄,如果沒有指定,默認繼承自當前的工作目錄。
使用env來指定新進程可見的環(huán)境變量。默認是process.env。
例如,運行ls -lh /usr,獲取stdout,stderr和退出代碼:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});例如:通過一個非常精巧的方法執(zhí)行'ps ax | grep ssh'
var spawn = require('child_process').spawn,
ps = spawn('ps', ['ax']),
grep = spawn('grep', ['ssh']);
ps.stdout.on('data', function (data) {
grep.stdin.write(data);
});
ps.stderr.on('data', function (data) {
console.log('ps stderr: ' + data);
});
ps.on('close', function (code) {
if (code !== 0) {
console.log('ps process exited with code ' + code);
}
grep.stdin.end();
});
grep.stdout.on('data', function (data) {
console.log('' + data);
});
grep.stderr.on('data', function (data) {
console.log('grep stderr: ' + data);
});
grep.on('close', function (code) {
if (code !== 0) {
console.log('grep process exited with code ' + code);
}
});options.stdio
stdio可能是以下幾個參數之一:
'pipe'-['pipe', 'pipe', 'pipe'],默認值'ignore'-['ignore', 'ignore', 'ignore']'inherit'-[process.stdin, process.stdout, process.stderr]或[0,1,2]
child_process.spawn()里的'stdio'參數是一個數組,它和子進程的fd相對應,它的值如下:
-
'pipe'- 創(chuàng)建在父進程和子進程間的pipe。管道的父進程端以child_process的屬性形式暴露給父進程,例如ChildProcess.stdio[fd]。為fds 0 - 2創(chuàng)建的管道也可以通過ChildProcess.stdin,ChildProcess.stdout和ChildProcess.stderr來獨立的訪問。 -
'ipc'- 在父進程和子進程間創(chuàng)建一個IPC通道來傳遞消息/文件描述符。一個子進程最多有1個IPC stdio文件標識。設置這個選項會激活ChildProcess.send() 方法。如果子進程向此文件標識寫入JSON消息,則會觸發(fā)ChildProcess.on('message') 。如果子進程是Node.js程序,那么IPC通道會激活process.send()和 process.on('message')。 -
'ignore'- 在子進程里不要設置這個文件標識,需要注意,Node總會為其spawn的進程打開fd 0-2。如果任何一個被ignored,node將會打開/dev/null并賦給子進程的fd。 -
Stream對象 - 共享一個tty、file、socket或刷(pipe)可讀或可寫流給子進程。該流底層(underlying)的文件標識在子進程中被復制給stdio數組索引對應的文件標識(fd)。 -
正數 - 這個整數被理解為一個在父進程中打開的文件標識,它和子進程共享,就和共享
Stream對象類似。 null,undefined- 使用默認值。 對于stdio fds 0、1 and 2 (換句話說,stdin、stdout或者stderr) ,pipe管道被建立。 對于fd 3及之后,默認是'ignore'。
例如:
var spawn = require('child_process').spawn;
// Child will use parent's stdios
spawn('prg', [], { stdio: 'inherit' });
// Spawn child sharing only stderr
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });
// Open an extra fd=4, to interact with programs present a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });options.detached
如果設置了detached選項,子進程將會被作為新進程組的leader,這使得子進程可以在父進程退出后繼續(xù)運行。
缺省情況下父進程會等detached的子進程退出。要阻止父進程等待一個這樣的子進程,調用child.unref()方法,則父進程的事件循環(huán)引用計數中將不會包含這個子進程。
detaching一個長期運行的進程,并重新將輸出指向文件:
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();使用detached選項來啟動一個長時間運行的進程時,進程不會在后臺保持運行,除非他提供了一個不連接到父進程的stdio。如果繼承了父進程的stdio,則子進程會繼續(xù)控制終端。
options.customFds
已廢棄,customFds允許指定特定文件描述符作為子進程的stdio。該API無法移植到所有平臺,因此被廢棄。使用customFds可以將新進程的 [stdin, stdout,stderr] 鉤到已有流上;-1表示創(chuàng)建新流。自己承擔使用風險。
參見:child_process.exec()和child_process.fork()
child_process.exec(command[, options], callback)
command{String} 要執(zhí)行的命令,空格分割options{Object}cwd{String} 子進程的當前工作目錄env{Object} 環(huán)境變量encoding{String} (默認: 'utf8')shell{String} 運行命令的shell(默認為: '/bin/sh' UNIX, 'cmd.exe' Windows, 該shell必須接收UNIX上的-c開關 ,或者Windows上的/s /c開關。Windows上,命令解析必須兼容cmd.exe。)timeout{Number} (默認: 0)maxBuffer{Number} (默認:200*1024)killSignal{String} (默認: 'SIGTERM')uid{Number} 設置進程里的用戶標識。 (見 setuid(2)。)gid{Number} 設置進程里的群組標識。(見 setgid(2)。)
callback{Function} 進程終止的時候調用error{Error}stdout{Buffer}stderr{Buffer}
- 返回: ChildProcess對象
在shell里執(zhí)行命令,并緩沖輸出。
var exec = require('child_process').exec,
child;
child = exec('cat *.js bad_file | wc -l',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});回調參數是(error, stdout, stderr)。如果成功,則,error值為null。 如果失敗,則error變?yōu)?code>Error的實例,error.code等于子進程退出碼,并且 error.signal會被設置為結束進程的信號名。
第二個參數可以設置一些選項。默認如下:
{ encoding: 'utf8',
timeout: 0,
maxBuffer: 200*1024,
killSignal: 'SIGTERM',
cwd: null,
env: null }如果timeout大于0,子進程運行時間超過timeout時會被終止。killSignal(默認: 'SIGTERM')能殺死子進程。maxBuffer設定了stdout或stderr的最大數據量,如果子進程的數量量超過了,將會被殺死。
(file[, args][, options][, callback])
file{String} 要運行的程序的文件名args{Array} 參數列表options{Object}cwd{String} 子進程的工作目錄env{Object} 環(huán)境encoding{String} (默認: 'utf8')timeout{Number} (默認: 0)maxBuffer{Number} (默認: 200*1024)killSignal{String} (默認: 'SIGTERM')uid{Number} 設置進程里的用戶標識。 (參見setuid(2)。)gid{Number} 設置進程里的群組標識。(參見setgid(2)。)
callback{Function} 進程終止的時候調用error{Error}stdout{Buffer}stderr{Buffer}
- 返回: ChildProcess對象
和child_process.exec()類似,不同之處在于這是執(zhí)行一個指定的文件,因此它比child_process.exec精簡些,參數相同。
child_process.fork(modulePath[, args][, options])
modulePath{String} 子進程里運行的模塊args{Array} 參數列表options{Object}cwd{String} 子進程的工作目錄env{Object} 環(huán)境execPath{String} 執(zhí)行文件路徑execArgv{Array} 執(zhí)行參數(默認:process.execArgv)silent{Boolean} 如果是 true ,子進程將會用父進程的 stdin, stdout, and stderr ,否則,將會繼承自父進程, 更多細節(jié),參見spawn()的stdio參數里的 "pipe" 和 "inherit" 選項(默認 false)uid{Number} 設置進程里的用戶標識。 (見 setuid(2)。)gid{Number} 設置進程里的群組標識。 (見 setgid(2)。)
- 返回: ChildProcess對象
這是spawn()的特殊例子,用于派生Node進程。除了擁有子進程的所有方法,它的返回對象還擁有內置通訊通道。參見child.send(message, [sendHandle])。
這些Nodes是全新的V8實例化,假設每個Node最少需要30ms的啟動時間,10mb的存儲空間,可想而知,創(chuàng)建幾千個Node是不太現實的。
options對象中的execPath屬性可以用于執(zhí)行文件(非當前node )創(chuàng)建子進程。這需要小心使用,缺省情況下fd表示子進程的NODE_CHANNEL_FD環(huán)境變量。該fa的輸入和輸出是以行分割的JSON對象。
創(chuàng)建同步進程
以下這些方法是同步的,意味著他會阻塞事件循環(huán),并暫停執(zhí)行代碼,直到spawned的進程退出。
同步方法簡化了任務進程,比如大為簡化在應用初始化加載/處理過程。
child_process.spawnSync(command[, args][, options])
command{String} 要執(zhí)行的命令args{Array} 參數列表options{Object}cwd{String} 子進程的當前工作目錄input{String|Buffer} 傳遞給spawned進程的值,這個值將會重寫stdio[0]stdio{Array} 子進程的stdio配置。env{Object} 環(huán)境變量uid{Number} 設置用戶進程的ID。 (參見setuid(2)。)gid{Number} 設置進程組的ID。 (參見setgid(2)。)timeout{Number} 子進程運行最大毫秒數。 (默認: undefined)killSignal{String} 用來終止子進程的信號。 (默認: 'SIGTERM')maxBuffer{Number}encoding{String} stdio輸入和輸出的編碼方式。 (默認: 'buffer')
- 返回: {Object}
pid{Number} 子進程的pidoutput{Array} stdio輸出的結果數組stdout{Buffer|String}output[1]的內容stderr{Buffer|String}output[2]的內容status{Number} 子進程的退出代碼signal{String} 用來殺死子進程的信號error{Error} 子進程錯誤或超時的錯誤代碼
spawnSync直到子進程關閉才會返回。超時或者收到killSignal信號,也不會返回,直到進程完全退出。進程處理完SIGTERM信號后并不會結束,直到子進程完全退出。
child_process.execFileSync(command[, args][, options])
command{String} 要執(zhí)行的命令args{Array} 參數列表options{Object}cwd{String} 子進程的當前工作目錄input{String|Buffer}傳遞給spawned進程的值,這個值將會重寫stdio[0]stdio{Array}子進程的stdio配置。 (默認: 'pipe')stderr默認情況下會輸出給父進程的' stderr除非指定了stdio
env{Object} 環(huán)境變量uid{Number} 設置用戶進程的ID。 (參見setuid(2)。)gid{Number} 設置進程組的ID。 (參見setgid(2)。)timeout{Number} 進程運行最大毫秒數。 (默認: undefined)killSignal{String} 用來終止子進程的信號。 (默認: 'SIGTERM')maxBuffer{Number}encoding{String} stdio輸入和輸出的編碼方式。 (默認: 'buffer')
- 返回: {Buffer|String} 來自命令的stdout
直到子進程完全退出,execFileSync才會返回。超時或者收到killSignal信號,也不會返回,直到進程完全退出。進程處理完SIGTERM信號后并不會結束,直到子進程完全退出。
如果進程超時,或者非正常退出,這個方法將會拋出異常。Error會包含整個child_process.spawnSync結果。
child_process.execSync(command[, options])
command{String} 要執(zhí)行的命令options{Object}cwd{String} 子進程的當前工作目錄input{String|Buffer} 傳遞給spawned進程的值,這個值將會重寫stdio[0]stdio{Array} 子進程的stdio配置。 (默認: 'pipe')stderr默認情況下會輸出給父進程的' stderr 除非指定了stdio
env{Object} 環(huán)境變量uid{Number} 設置用戶進程的ID。 (參見setuid(2)。)gid{Number} 設置進程組的ID。 (參見setgid(2)。)timeout{Number} 進程運行最大毫秒數。 (默認: undefined)killSignal{String} 用來終止子進程的信號。 (默認: 'SIGTERM')maxBuffer{Number}encoding{String} stdio輸入和輸出的編碼方式。 (默認: 'buffer')
- 返回: {Buffer|String}來自命令的stdout
直到子進程完全退出,execSync才會返回。超時或者收到killSignal信號,也不會返回,直到進程完全退出。進程處理完SIGTERM信號后并不會結束,直到子進程完全退出。
如果進程超時,或者非正常退出,這個方法將會拋出異常。Error會包含整個child_process.spawnSync結果。
以上就是Node.js官方文檔中有關子進程的介紹。
網頁標題:創(chuàng)新互聯Node.js教程:Node.js子進程
標題來源:http://m.fisionsoft.com.cn/article/dppscco.html


咨詢
建站咨詢
