引
在Node.js中上陕,只使用一個線程來執(zhí)行所有的操作。因此拓春,如果在應用程序中存在某個操作需要大量消耗CPU資源的情況释簿,則其他操作都會受到一定的影響。例如痘儡,當服務器正在執(zhí)行一個非常消耗CPU資源的操作辕万,則在該操作執(zhí)行之后接收的客戶端請求都需要等待該操作執(zhí)行完畢后才能被處理。沉删、
近些年來,服務器一般都開始使用多核CPU或者多CPU醉途,許多服務器應用程序都開始依靠多線程或多進程機制來處理這些請求矾瑰,以便可以更好地利用這些CPU資源。在Node.js中隘擎,同樣提供一個child_process模塊殴穴。通過該模塊的使用,在Node.js應用程序的主進程運行之后,可以開啟多個子進程采幌。在多個子進程之間可以共享內存空間劲够,可以通過子進程之間的互相通信來實現(xiàn)信息的交換,多個子進程之間也可以通過共享端口的方式將請求分配給多個子進程來執(zhí)行休傍。
使用spawn方法開啟子進程
在child_process模塊中征绎,提供多個可以開啟子進程的方法
首先,可以使用spawn方法開啟一個用于運行某個命令的子進程磨取。
child_process.spawn(command,[args],[options])
- command:-為一個字符串人柿,用于指定需要運行的命令
- arg:參數(shù)值為一個數(shù)組,其中存放了所有運行該命令時需要使用的參數(shù)忙厌,參數(shù)的指定順序與數(shù)組中的元素順序保持一致凫岖,如果不使用args參數(shù),默認參數(shù)值為一個空數(shù)組逢净。
- options:參數(shù)值為一個對象哥放,用于指定開啟子進程時使用的選項。在該對象中爹土,可以指定的屬性及屬性值如下
- cwd:屬性值為一個字符串婶芭,用于指定子進程的當前工作目錄,可以使用相對路徑或絕對路徑來指定該目錄着饥。
- stdio:屬性值為一個字符串或一個存放了三個元素的數(shù)組犀农,用于設置子進程的標準輸入/輸出。
- customFds:屬性值為一個數(shù)組宰掉,用于指定為子進程的標準輸入/輸出指定文件描述符呵哨,目前該屬性值已不推薦使用。
- env:屬性值為一個對象轨奄,用于以“鍵名/鍵值”的形式為子進程指定環(huán)境變量孟害。不指定該屬性值時子進程中沒有可以使用的環(huán)境變量,而不是使用process.env屬性值中指定的環(huán)境變量挪拟。
- detached:屬性值為一個布爾值挨务。如果屬性值為true,該子進程為一個進程組中的領頭進程玉组。如果該進程為領頭進程谎柄,當其父進程已不存在時,子進程也可以獨立存在惯雳。該屬性的默認屬性值為false朝巫。
- uid:屬性值為一個數(shù)值。用于設置子進程的用戶ID石景,只在POSIX(即非Windows)操作系統(tǒng)中有效劈猿。
- gid:屬性值為一個數(shù)值拙吉。用于設置子進程的組ID,只在POSIX(即非Windows)操作系統(tǒng)中有效揪荣。
- 'pipe':用于在父進程與子進程之間創(chuàng)建一個管道筷黔。在父進程中可以通過代表子進程的ChildProcess對象的stdio[0]屬性值訪問子進程的標準輸入,可以通過ChildProcess對象的stdio[1]屬性值訪問子進程的標準輸出仗颈,可以通過ChildProcess象的stdio[2]屬性值訪問子進程的標準錯誤輸出佛舱。
- 'ipc':用于在父進程與子進程之間創(chuàng)建一個專用于傳遞消息或文件描述符的IPC通道。一個子進程最多可以擁有一個IPC通道文件描述符揽乱。設置該選項使子進程的send方法可以被使用名眉。如果子進程在這個文件描述符中寫入JSON格式的消息,將會觸發(fā)子進程對象的message事件凰棉。如果子進程運行Node.js應用程序损拢,IPC通道的存在將使進程對象的send方法可以被使用,也可使進程對象的message事件被觸發(fā)撒犀。
- 'ignore':用于指定不為子進程設置文件描述符福压。在Node.js中為子進程使用0文件描述符(用于標準輸入)、1文件描述符(用于標準輸出)以及2文件描述(用于標準錯誤輸出)或舞,如果這些文件描述符被忽略荆姆,Node.js將會把子進程的文件描述符定義為/dev/null(重定向到空設備文件)。
- Stream對象:用于指定子進程與父進程共享一個終端設備映凳、文件胆筒、端口或管道。數(shù)據(jù)流的底層文件描述符將在子進程中被復制诈豌。
- 正整數(shù)值:用于指定父進程中被打開的文件描述符仆救。該文件描述符在子進程中被共享,其效果與在父進程及子進程中共享一個Stream對象一樣矫渔。
- null或undefined:使用默認值彤蔽。對于標準輸入/輸出來說,在子進程中創(chuàng)建與父進程相連接的管道庙洼。對于用于讀取文件的文件描述符3來說顿痪,在子進程中被忽略。
spawn方法返回一個隱式創(chuàng)建的代表子進程的ChildProcess對象油够。
spawn使用示例:
var cp=require('child_process');
var sp1 =cp.spawn('node',['test1.js','one','two','three','four'],{cwd:'./test'});
var sp2 =cp.spawn('node',['test2.js'],{stdio:'pipe'});
sp1.stdout.on('data',function (data) {
console.log('子進程標準輸出: '+data);
sp2.stdin.write(data);
});
sp1.on('exit',function(code,signal) {
console.log('子進程退出蚁袭,退出代碼為:'+code);
process.exit();
});
父進程向子進程發(fā)送信號
在父進程中,可以使用子進程對象的kill方法向子進程發(fā)送信號叠聋。
child.kill([signal])
可以使用一個可選參數(shù)撕阎,參數(shù)值為用于描述該信號的字符串。默認參數(shù)值為’SIGTERM’(用于強制關閉進程)碌补。
使用子進程的kill方法關閉子進程
var cp=require('child_process');
var sp1 =cp.spawn('node',['test1.js','one','two','three','four'],{cwd:'./test'});
var sp2 =cp.spawn('node',['test2.js'],{stdio:'pipe'});
sp1.stdout.on('data',function (data) {
console.log('子進程標準輸出: '+data);
sp2.stdin.write(data);
sp1.kill();
});
sp1.on('exit',function(code,signal) {
if(!code)
console.log('子進程退出虏束,退出信號為:'+signal);
else
console.log('子進程退出,退出代碼為:'+code);
process.exit();
});
sp1.on('error',function (err) {
console.log('子進程開啟失敗: '+err);
process.exit();
});
如果利用spawn方法的options參數(shù)值對象的stdio屬性中的'ipc'字符串值在父進程與子進程之間創(chuàng)建一個IPC通道厦章,那么镇匀,當該通道關閉時,將觸發(fā)子進程對象的disconnect事件袜啃。
var cp=require('child_process');
var sp1 =cp.spawn('node',['test1.js','one','two','three','four'],{cwd:'./test',stdio:['ipc','pipe','ignore']});
var sp2 =cp.spawn('node',['test2.js'],{stdio:['pipe']});
sp1.stdout.on('data',function (data) {
console.log('子進程標準輸出: '+data);
sp2.stdin.write(data);
});
sp1.on('exit',function(code,signal) {
console.log('子進程退出汗侵,退出代碼為:'+code);
process.exit();
});
sp1.on('error',function (err) {
console.log('子進程開啟失敗: '+err);
process.exit();
});
sp1.on('disconnect', function() {
console.log('IPC通道被關閉。');
});
使用fork方法開啟子進程
在child_process模塊中群发,可以使用fork方法開啟一個專用于運行Node.js中的某個模塊文件的子進程晰韵。
child_process.fork(modulePath,[args],[options])
- modulePath:參數(shù)值為一個字符串,用于指定需要運行的Node.js模塊文件路徑及文件名熟妓。
- arg:參數(shù)值為一個數(shù)組雪猪,其中存放了所有運行該模塊文件時需要使用的參數(shù),參數(shù)的指定順序與數(shù)組中的元素順序保持一致起愈,如果不使用args參數(shù)只恨,默認參數(shù)值為一個空數(shù)組。
- options:參數(shù)值為一個對象抬虽,用于指定開啟子進程時使用的選項
- cwd:屬性值為一個字符串官觅,用于指定子進程的當前工作目錄,可以使用相路徑或絕對路徑來指定該目錄阐污。
- env:屬性值為一個對象休涤,用于以“鍵名/鍵值”的形式為子進程指定環(huán)境變量。不指定該屬性值時子進程中沒有可以使用的環(huán)境變量笛辟,而不是使用process.env屬性值中指定的環(huán)境變量功氨。
- encoding:屬性值為一個字符串,用于指定標準輸出及標準錯誤輸出數(shù)據(jù)的編碼格式隘膘。默認屬性值為“utf8”疑故。
- silent:屬性值為一個布爾值,當屬性值為false時弯菊,子進程對象與父進程對象共享標準輸入/輸出纵势,當屬性值為true時,子進程對象與父進程對象不共享標準輸入/輸出管钳。默認屬性值為false钦铁。
fork方法返回一個隱式創(chuàng)建的代表子進程的ChildProcess對象。
在使用fork方法時才漆,當子進程中所有輸入/輸出操作執(zhí)行完畢后牛曹,子進程不會自動退出。必須使用process.exit()方法將其顯式退出醇滥。
當使用fork方法開啟子進程后黎比,可以使用子進程對象的send方法在父進程中向子進程發(fā)送消息超营,在子進程中也可以使用進程對象的send方法向父進程發(fā)送消息,
child.send(message,[sendHandle]) //
在父進程中向子進程發(fā)送消息
process.send(message,[sendHandle]) //
在父進程中向主進程發(fā)送消息
- message:參數(shù)值為一個對象阅虫,用于指定需要發(fā)送的消息演闭。
- sendHandle:參數(shù)可以指定為一個當接收到對方發(fā)送消息后執(zhí)行的回調函數(shù),也可以為一個服務器對象或socket端口對象颓帝,以達到在父進程與子進程之間共享該對象的目的米碰。
子父進程共享HTTP服務器
父進程
var http = require('http');
var child_process = require('child_process');
var fs = require('fs');
var child = child_process.fork('child.js');
var server = net.createServer();
server.listen(1337, '127.0.0.1', function () {
child.send('server', server);
console.log('父進程中的服務器已創(chuàng)建。');
var httpServer = http.createServer();
httpServer.on('request', function (req, res) {
if(req.url!=="/favicon.ico"){
var sum=0;
for(var i=0;i<1000000;i++){
sum+=i;
}
res.write("客戶端請求在父進程中被處理购城。");
res.end("sum="+sum);
}
});
httpServer.listen(server);
});
子進程
var http = require('http');
process.on('message', function (msg,server) {
if (msg === 'server') {
console.log('子進程中的服務器已創(chuàng)建吕座。');
var httpServer = http.createServer();
httpServer.on('request', function (req, res) {
if(req.url!=="/favicon.ico"){
sum=0;
for(var i=0;i<1000000;i++){
sum+=i;
}
res.write("客戶端請求在子進程中被處理。");
res.end("sum="+sum);
}
});
httpServer.listen(server);
}
});
連續(xù)向服務端發(fā)送10次請求
var http = require('http');
var options = {
hostname: 'localhost',
port: 1337,
path: '/',
method: 'GET'
};
for(var i=0;i<10;i++){
var req = http.request(options,function(res) {
res.on('data', function (chunk) {
console.log('響應內容: '+chunk);
});
});
req.end();
}
父進程與子進程共享socket端口對象
父進程
var child = require('child_process').fork('child.js');
var server = require('net').createServer();
server.on('connection', function(socket) {
if (socket.remoteAddress!== '192.168.1.100') {
child.send('socket', socket);
return;
}
socket.end('客戶端請求被父進程處理瘪板。');
});
server.listen(42367,'192.168.1.100');
子進程
process.on('message', function(m,socket) {
if (m === 'socket') {
socket.end('客戶端請求被子進程處理吴趴。');
}
});
使用exec方法開啟子進程
在child_process模塊中,可以使用exec方法開啟一個用于運行某個命令的子進程并緩存子進程中的輸出結果篷帅。
child_process.exec(command,[options],[callback])
- command:參數(shù)值為一個字符串史侣,用于指定需要運行的命令。
- options:參數(shù)值為一個對象魏身,用于指定開啟子進程時使用的選項惊橱。
- cwd:屬性值為一個字符串,用于指定子進程的當前工作目錄箭昵,可以使用相對路徑或絕對路徑來指定該目錄税朴。默認屬性值為null。
- env:屬性值為一個對象家制,用于以“鍵名/鍵值”的形式為子進程指定環(huán)境變量正林。不指定該屬性值時,子進程中沒有可以使用的環(huán)境變量颤殴,而不是使用process.env屬性值中指定的環(huán)境變量觅廓。默認屬性值為null。
- encoding:屬性值為一個字符串涵但,用于指定標準輸出及標準錯誤輸出數(shù)據(jù)的編碼格式杈绸。默認屬性值為“utf8”。
- timeout:屬性值為一個整數(shù)值矮瘟,用于指定子進程的超時時間瞳脓,單位為毫秒。當子進程的運行時間超過該時間時澈侠,Node.js將使用killSignal屬性值所指定的信號強制關閉該子進程劫侧。默認屬性值為0,表示不限定子進程的運行時間。
- maxbuffer:屬性值為一個整數(shù)值烧栋,用于指定用于緩存標準輸出數(shù)據(jù)及標準錯誤輸出數(shù)據(jù)的緩存區(qū)的最大長度写妥,如果標準輸出數(shù)據(jù)及標準錯誤輸出數(shù)據(jù)的總長度超過該屬性值,子進程將被強制關閉劲弦。默認屬性值為200*1024耳标。
- killSignal:用于指定關閉子進程的信號醇坝,默認屬性值為'SIGTERM'邑跪。
exec方法中使用的callback參數(shù)用于指定子進程終止時調用的回調函數(shù)
function(error, stdout, stderr) {
//回調函數(shù)代碼略
}
- error:參數(shù)值為子進程被異常終止時觸發(fā)的異常對象。
- stderr:為緩存了子進程標準錯誤輸出數(shù)據(jù)的緩存區(qū)對象呼猪。
- stdout:為緩存了子進程標準輸出數(shù)據(jù)的緩存區(qū)對象
exec方法與spawn方法的最大區(qū)別是画畅,spawn方法可以在父進程中實時接收子進程中輸出的標準輸出流數(shù)據(jù)或標準錯誤輸出流數(shù)據(jù),因此是一個異步方法宋距。如果使用exec方法轴踱,那么父進程必須等待子進程中的標準輸出流數(shù)據(jù)或標準錯誤輸出流數(shù)據(jù)全部緩存完畢后才能接收這些數(shù)據(jù),因此是一個同步方法谚赎。
使用execFile方法開啟子進程
在child_process模塊中淫僻,可以使用execFile方法開啟一個專用于運行某個可執(zhí)行文件的子進程。
child_process.execFile(file,[args],[options],[callback])
- file:參數(shù)值為一個字符串壶唤,用于指定需要運行的可執(zhí)行文件路徑及文件名雳灵。
- args:參數(shù)值為一個數(shù)組,其中存放了所有運行該文件時需要使用的參數(shù)闸盔,參數(shù)的指定順序與數(shù) 組中的元素順序保持一致悯辙,如果不使用args參數(shù),默認參數(shù)值為一個空數(shù)組迎吵。
- options:參數(shù)值為一個對象躲撰,用于指定開啟子進程時使用的選項。在該對象中击费,可以指定的屬性及屬性值與exec方法中所使用的options參數(shù)值對象中可以指定的屬性及屬性值完全相同拢蛋。
- callback:用于指定子進程終止時調用的回調函數(shù),該回調函數(shù)的指定方法與exec方法中使用的callback參數(shù)值回調函數(shù)的指定方法完全相同蔫巩。