Node.js進(jìn)程管理之子進(jìn)程詳解
一、理論
之前看多進(jìn)程這一章節(jié)時(shí)發(fā)現(xiàn)這塊東西挺多,寫Process模塊的時(shí)候也有提到,今天下午午休醒來靜下心來好好的看了一遍,發(fā)現(xiàn)也不是太難理解。
Node.js是單線程的,對于現(xiàn)在普遍是多處理器的機(jī)器是一種浪費(fèi),怎么能利用起來呢?于是child_process模塊出現(xiàn)了。child_process模塊可以在其他進(jìn)程上產(chǎn)生、派生,并執(zhí)行工作。
child_process模塊提供了一個ChildProcess的新類,它可以作為從父進(jìn)程訪問子進(jìn)程的表示形式。Process模塊也是ChildProcess對象。當(dāng)你從父模塊訪問process時(shí),它是父ChildProcess對象,當(dāng)你從子進(jìn)程訪問Process是,它是ChildProcess對象
了解一個對象無外乎事件、方法、屬性。ChildProcess也是一樣。下面列出一些常用的事件、方法和屬性。
事件:
message:當(dāng)ChildProcess對象調(diào)用send()方法來發(fā)送數(shù)據(jù)時(shí)觸發(fā)。
error:在工作進(jìn)程中出現(xiàn)錯誤時(shí)發(fā)出。該處理程序接收一個錯誤對象作為唯一的參數(shù)。
exit:當(dāng)工作進(jìn)程結(jié)束時(shí)發(fā)出。該處理程序接收兩個參數(shù),code,signal.
close:當(dāng)工作進(jìn)程的所有stdio流都已經(jīng)終止的時(shí)候發(fā)出。與exit不同的是,因?yàn)槎鄠€進(jìn)程可以共享相同的stdio流。
disconnect:當(dāng)disconnect()在一個工作進(jìn)程上被調(diào)用時(shí)發(fā)出。
方法:
kill([signal]):導(dǎo)致操作系統(tǒng)發(fā)送一個kill信號給子進(jìn)程。默認(rèn)是SIGTERM.
send(message,[sendHandle]):將消息發(fā)送到句柄。消息可是字符串或?qū)ο?。sendhandle可以把TCP Server或socket對象發(fā)送到客戶端。這允許客戶端進(jìn)程共享相同的端口和地址。
disconnect():關(guān)閉父進(jìn)程與子進(jìn)程之間的進(jìn)程通信(或IPC)通道,并把父進(jìn)程和子進(jìn)程的連接標(biāo)志都設(shè)置為false。
屬性:
stdin:輸入Writable流。
stdout:標(biāo)準(zhǔn)輸出Readable流。
strerr:用于輸出錯誤的標(biāo)準(zhǔn)輸出Readable流。
pid:進(jìn)程的ID。
connected:一個布爾值。在disconnect()被調(diào)用后,它被設(shè)置為false,當(dāng)是false時(shí),就不能將消息發(fā)送給子進(jìn)程。
二、實(shí)踐
1.exec()在另一進(jìn)程執(zhí)行一個系統(tǒng)命令
exec()函數(shù)在一個子shell中執(zhí)行系統(tǒng)命令。幾乎可以執(zhí)行能從控制臺提示符下執(zhí)行的任何東西,如二進(jìn)制可執(zhí)行文件、shell腳本、Python腳本或批處理文件。
exec(command,[options],callback)函數(shù)返回一個ChildProcess對象
command:字符串,指定在子shell中執(zhí)行的命令。
options:對象,指定執(zhí)行命令時(shí)使用的設(shè)置。選項(xiàng)如下:
- cwd:指定子進(jìn)程執(zhí)行的當(dāng)前工作目錄
- env:一個對象,指定property:value作為環(huán)境的鍵/值對
- encoding:指定存儲命令的輸出時(shí)輸出緩沖區(qū)使用的編碼
- maxBuffer:指定stdout、stderror輸出緩沖區(qū)的大小。默認(rèn)200*1024.
- timeout:指定父進(jìn)程在殺掉子進(jìn)程之前,如果子進(jìn)程未完成等待的毫秒數(shù)。默認(rèn)0
- killSignal:指定終止子進(jìn)程時(shí)使用的kill信號。默認(rèn)SIGTERM。
callback:接收error、stdout、stderr3個參數(shù)。
var childProcess = require('child_process'); var options = {maxBuffer:100*1024, encoding:'utf8', timeout:5000}; var child = childProcess.exec('dir /B', options, function (error, stdout, stderr) { if (error) { console.log(error.stack); console.log('Error Code: '+error.code); console.log('Error Signal: '+error.signal); } console.log('Results: \n' + stdout); if (stderr.length){ console.log('Errors: ' + stderr); } }); child.on('exit', function (code) { console.log('Completed with code: '+code); });
輸出結(jié)果:
"C:\Program Files (x86)\JetBrains\WebStorm 11.0.3\bin\runnerw.exe" F:\nodejs\node.exe child_process_exec.js Completed with code: 0 Results: chef.js child_fork.js child_process_exec.js child_process_exec_file.js child_process_spawn.js cluster_client.js cluster_server.js cluster_worker.js file.txt process_info.js Process finished with exit code 0
2.execFile()在另一個進(jìn)程上執(zhí)行一個可執(zhí)行文件
它與exec()相似,不同的是execFile()沒有使用子shell,執(zhí)行的命令必須是一個二進(jìn)制可執(zhí)行文件Linux的shell腳本和Windows的批處理文件不能使用ecexFile().
execFile(file,args,options,callback)也是返回一個ChildProcess。
file:字符串,執(zhí)行要執(zhí)行的可執(zhí)行文件的路徑。
args:數(shù)組,指定傳遞給可執(zhí)行文件的命令行參數(shù)。
options:參考exec()的。
callback:參考exec().
var childProcess = require('child_process'); var options = {maxBuffer:100*1024, encoding:'UTF-16', timeout:5000}; var child = childProcess.execFile('ping.exe', ['-n', '1', 'baidu.com'], options, function (error, stdout, stderr) { if (error) { console.log(error.stack); console.log('Error Code: '+error.code); console.log('Error Signal: '+error.signal); } console.log('Results: \n' + stdout.toString()); if (stderr.length){ console.log('Errors: ' + stderr.toString()); } }); child.on('exit', function (code) { console.log('Child completed with code: '+code); });
3.spawn()在另一個Node.js實(shí)例中產(chǎn)生一個進(jìn)程
spawn(cmd,[args],[options])函數(shù)產(chǎn)生一個進(jìn)程,連接它們之間的stdio、stdout、stderr的管道,然后在新的線程中使用spawn()執(zhí)行文件。它和上面兩個的主要區(qū)別是產(chǎn)生的進(jìn)程中的stdin可以進(jìn)行配置,并且stdout、stderr都是父進(jìn)程中的Readable流。這意味著exec()、execFile()必須先執(zhí)行完成,才能讀取緩沖區(qū)輸出,但一旦一個spawn()進(jìn)程的輸出數(shù)據(jù)已被寫入就可以讀取它(這個可以從它們3個的輸出結(jié)果的順序可以看出,上面兩個都是先執(zhí)行exit事件,而spawn()exit處理是在后面)。
cmd、args和上面兩個的一樣。options也可以設(shè)置cwd、env,還可以設(shè)置detached、stdio。
detached:布爾值,true時(shí)使子進(jìn)程成為新進(jìn)程組的組長,即使父進(jìn)程退出,也會繼續(xù),可以使用child_unref()使得父進(jìn)程退出之前不等待子進(jìn)程
stdio:定義子進(jìn)程stdio配置([stdin,stdout,stderr]).默認(rèn)[0,1,2].此字符串定義每個輸入輸出流的配置。
var spawn = require('child_process').spawn; var options = { env: {user:'brad'}, detached:false, stdio: ['pipe','pipe','pipe'] }; var child = spawn('netstat', ['-e']); child.stdout.on('data', function(data) { console.log(data.toString()); }); child.stderr.on('data', function(data) { console.log(data.toString()); }); child.on('exit', function(code) { console.log('Child exited with code', code); });
4.實(shí)現(xiàn)子派生
Node.js提供了另外一種進(jìn)程產(chǎn)生方式——派生。它主要是執(zhí)行在一個單獨(dú)的處理器上運(yùn)行另外一個V8引擎實(shí)例中的Node.js模塊代碼??梢杂门缮鷣聿⑿羞\(yùn)行多個服務(wù)。不過這需要時(shí)間來運(yùn)轉(zhuǎn)V8的一個新實(shí)例,每個實(shí)例需要大約10M的內(nèi)存,所以應(yīng)該把派生的進(jìn)程設(shè)計(jì)為存活期更長的,不需要大量派生的進(jìn)程。與spawn不同的是,它不能為子進(jìn)程配置stdio??梢允褂肅hildProcess對象中的send()機(jī)制在父進(jìn)程與子進(jìn)程間通信。
fork(modulePath,[args],[options])對象也是返回一個ChildProcess對象。
modulePath:字符串,指定被新的Node.js實(shí)例啟動的JavaScript文件路徑。
args:數(shù)組,指定傳遞給node命令的命令行參數(shù)。
options:參數(shù)對象,指定執(zhí)行命令時(shí)使用的設(shè)置。
cwd、env上面有。
encoding:指定數(shù)據(jù)寫入輸出流時(shí)和穿越send()IPC機(jī)制時(shí)使用的編碼
execPath:指定用于創(chuàng)建產(chǎn)生Node.js進(jìn)程的可執(zhí)行文件。
silent:一個布爾值,true時(shí)將導(dǎo)致派生的進(jìn)程中的stdout和stderr不與父進(jìn)程相關(guān)聯(lián),默認(rèn)false。
Child.send()父進(jìn)程向子進(jìn)程發(fā)送消息,Process.send()是子進(jìn)程向父進(jìn)程發(fā)送消息。
var child_process = require('child_process'); var options = { env:{user:'Brad'}, encoding:'utf8' }; function makeChild(){ var child = child_process.fork('chef.js', [], options); child.on('message', function(message) { console.log('Served: ' + message); }); return child; } function sendCommand(child, command){ console.log("Requesting: " + command); child.send({cmd:command}); } var child1 = makeChild(); var child2 = makeChild(); var child3 = makeChild(); sendCommand(child1, "makeBreakfast"); sendCommand(child2, "makeLunch"); sendCommand(child3, "makeDinner");
process.on('message', function(message, parent) { var meal = {}; switch (message.cmd){ case 'makeBreakfast': meal = ["ham", "eggs", "toast"]; break; case 'makeLunch': meal = ["burger", "fries", "shake"]; break; case 'makeDinner': meal = ["soup", "salad", "steak"]; break; } process.send(meal); });
輸出結(jié)果:
"C:\Program Files (x86)\JetBrains\WebStorm 11.0.3\bin\runnerw.exe" F:\nodejs\node.exe child_fork.js Requesting: makeBreakfast Requesting: makeLunch Requesting: makeDinner Served: ham,eggs,toast Served: burger,fries,shake Served: soup,salad,steak
上面的代碼是在主進(jìn)程中創(chuàng)建3個子進(jìn)程,父進(jìn)程給子進(jìn)程發(fā)消息,子進(jìn)程接收并給父進(jìn)程發(fā)消息。
到此這篇關(guān)于Node.js進(jìn)程管理之子進(jìn)程的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
分享五個Node.js開發(fā)的優(yōu)秀實(shí)踐?
這篇文章主要介紹了分享五個Node.js開發(fā)的優(yōu)秀實(shí)踐,文章圍繞主題展開詳細(xì)的分享內(nèi)容,需要的小伙伴可以參考一下,希望對你的工作有所幫助2022-04-04nodejs 全局變量和全局對象知識點(diǎn)及用法詳解
在本篇文章里小編給大家整理的是一篇關(guān)于nodejs 全局變量和全局對象知識點(diǎn)及用法等內(nèi)容,對此有興趣的朋友們可以學(xué)習(xí)參考下。2021-12-12詳解如何在Node.js中執(zhí)行CPU密集型任務(wù)
Node.js通常被認(rèn)為不適合CPU密集型應(yīng)用程序,Node.js的工作原理使其在處理I/O密集型任務(wù)時(shí)大放異彩,雖然執(zhí)行CPU密集型任務(wù)肯定不是Node的主要使用場景,但是我們依舊有方法來改善這些問題,本文詳細(xì)給大家介紹了如何在Node.js中執(zhí)行CPU密集型任務(wù)2023-12-12nodejs獲取表單數(shù)據(jù)的三種方法實(shí)例
在開發(fā)中經(jīng)常需要獲取form表單的數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于nodejs獲取表單數(shù)據(jù)的三種方法,方法分別是form表單傳遞、ajax請求傳遞以及表單序列化,需要的朋友可以參考下2021-06-06window系統(tǒng)管理多版本node的實(shí)現(xiàn)
存在不同項(xiàng)目使用npm時(shí)所需要的版本不一致,又不想每次都卸載又重新安裝node,這時(shí)候就需要多版本管理器,本文主要介紹了window系統(tǒng)管理多版本node的實(shí)現(xiàn),感興趣的可以了解一下2024-02-02Win7系統(tǒng)中如何安裝高版本的NodeJS(親測有效!)
Node.js是基于Chrome V8引擎的JavaScript運(yùn)行環(huán)境,能夠使JavaScript在服務(wù)器端運(yùn)行,這篇文章主要給大家介紹了關(guān)于Win7系統(tǒng)中如何安裝高版本的NodeJS的相關(guān)資料,需要的朋友可以參考下2023-12-12Node.js學(xué)習(xí)之TCP/IP數(shù)據(jù)通訊(實(shí)例講解)
下面小編就為大家?guī)硪黄狽ode.js學(xué)習(xí)之TCP/IP數(shù)據(jù)通訊(實(shí)例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10