node.js中process進(jìn)程的概念和child_process子進(jìn)程模塊的使用方法示例
本文實(shí)例講述了node.js中process進(jìn)程的概念和child_process子進(jìn)程模塊的使用方法。分享給大家供大家參考,具體如下:
進(jìn)程,你可以把它理解成一個(gè)正在運(yùn)行的程序。node.js中每個(gè)應(yīng)用程序都是進(jìn)程類的實(shí)例對(duì)象。
node.js中有一個(gè) process 全局對(duì)象,通過(guò)它我們可以獲取,運(yùn)行該程序的用戶,環(huán)境變量等信息。
一、process 對(duì)象
console.log('可執(zhí)行文件絕對(duì)路徑', process.execPath); console.log('版本號(hào)', process.version); console.log('依賴庫(kù)的版本號(hào)', process.versions); console.log('運(yùn)行平臺(tái)', process.platform); console.log('標(biāo)準(zhǔn)輸入流', process.stdin); console.log('標(biāo)準(zhǔn)輸出流', process.stdout); console.log('標(biāo)準(zhǔn)錯(cuò)誤流', process.stderr); console.log('命令行參數(shù)數(shù)組', process.argv); console.log('系統(tǒng)環(huán)境變量', process.env); console.log('進(jìn)程ID', process.pid); console.log('標(biāo)題', process.title); console.log('處理器架構(gòu)', process.arch);
通過(guò) memoryUsage() 查看內(nèi)存使用量:
console.log(process.memoryUsage());
- rss 表示進(jìn)程占用的內(nèi)存,包括堆,棧,代碼段。
- heapTotal 表示堆占用的內(nèi)存。
- heapUsed 表示堆使用的部分。
- external 表示外部使用的部分,C++對(duì)象占用的。
對(duì)象,字符串,閉包存放于堆內(nèi)存,變量存放于棧內(nèi)存,js源代碼存放于代碼段。
console.log(process.memoryUsage()); let buf = Buffer.alloc(1024 * 1024 * 1024); console.log(process.memoryUsage());
當(dāng)我們通過(guò)Buffer創(chuàng)建一個(gè)足夠大的變量時(shí),這時(shí)只能借助于外部?jī)?nèi)存,使用C++去完成。node.js能夠使用的內(nèi)存上限是1.7G。
使用 chdir() 修改程序當(dāng)前的工作目錄,通過(guò) cwd() 獲取當(dāng)前工作目錄。
console.log(process.cwd()); //修改程序當(dāng)前的工作目錄 process.chdir('../'); console.log(process.cwd());
通過(guò) exit() 來(lái)結(jié)束進(jìn)程
process.exit(0);
調(diào)用 exit() 結(jié)束進(jìn)程時(shí),會(huì)觸發(fā) 'exit' 事件。
process.on('exit', function () { console.log('程序退出了'); }); process.exit(0);
通過(guò) kill() 給指定進(jìn)程發(fā)送信號(hào)
SIGINT 程序終止信號(hào),當(dāng)用戶按下ctrl+c時(shí)發(fā)出,將通知進(jìn)程終止。
SIGTERM 程序結(jié)束信號(hào),通知程序正常退出,kill()方法默認(rèn)就是這個(gè)信號(hào)。
process.kill(process.pid, 'SIGINT');
通過(guò) uptime() 返回程序運(yùn)行的時(shí)間
console.log(process.uptime());
通過(guò) hrtime() 計(jì)算代碼段運(yùn)行時(shí)間,hrtime() 返回一個(gè)數(shù)組,第一個(gè)表示秒,第二個(gè)表示納秒
let start = process.hrtime(); let sum = 0; for (i = 0; i < 1000000000; i++) { sum += i; } let end = process.hrtime(start); console.log('耗時(shí) : ', end[0], '秒');
當(dāng)程序拋出一個(gè)沒有被捕獲的異常時(shí),觸發(fā) 'uncaughtException' 事件。
process.on('uncaughtException', function (err) { console.log('捕獲了一個(gè)未被處理的異常'); console.log(err); }); //調(diào)用一個(gè)未定義的函數(shù) test();
進(jìn)程接收到一個(gè)信號(hào)時(shí),會(huì)觸發(fā)信號(hào)事件,我們可以監(jiān)聽到該事件。
//讓標(biāo)準(zhǔn)輸入流處于流動(dòng)模式,讓程序無(wú)法退出 process.stdin.resume(); process.on('SIGINT', function () { console.log('程序退出'); process.exit(0); }); process.on('SIGTERM', function () { console.log('程序結(jié)束'); });
二、子進(jìn)程模塊child_process的使用
我們都知道node.js是單線程的,如果某一個(gè)操作需要消耗大量資源和時(shí)間,會(huì)導(dǎo)致程序整體性能下降。
我們可以創(chuàng)建子進(jìn)程,讓子進(jìn)程去跑那些費(fèi)時(shí)費(fèi)力的操作,而主線程該干嘛干嘛。
子進(jìn)程間可以共享內(nèi)存,通過(guò)互相通信來(lái)完成數(shù)據(jù)的交換。
1、通過(guò) spawn() 創(chuàng)建子進(jìn)程
const {spawn} = require('child_process'); //參數(shù)一表示,要執(zhí)行的命令 //參數(shù)二表示,運(yùn)行該命令的參數(shù) //參數(shù)三表示,創(chuàng)建子進(jìn)程的配置 let cp1 = spawn('node', ['1.js'], { //cwd表示當(dāng)前子進(jìn)程的工作目錄 cwd: process.cwd(), //子進(jìn)程的環(huán)境變量 env: process.env, //子進(jìn)程的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,錯(cuò)誤,的配置 //pipe表示,父進(jìn)程與子進(jìn)程間建立管道,父進(jìn)程可以訪問子進(jìn)程對(duì)應(yīng)的輸入,輸出,和錯(cuò)誤 //ipc表示,父進(jìn)程與子進(jìn)程間建立一個(gè)專門用來(lái)傳遞消息的IPC通道,子進(jìn)程調(diào)用send()方法向子進(jìn)程發(fā)送消息,并觸發(fā)'message'事件 //ignore表示,忽略子進(jìn)程的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,錯(cuò)誤。 //inherit表示,子進(jìn)程共享父進(jìn)程的標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,錯(cuò)誤。 //stream表示,父進(jìn)程與子進(jìn)程共享一個(gè)流,比如文件流或socket。 //正整數(shù)表示,父進(jìn)程打開的文件描述符,與子進(jìn)程共享,比如文件的fd。類似stream流對(duì)象共享。 //null或undefined表示,父進(jìn)程與子進(jìn)程間創(chuàng)建管道 stdio: ['pipe', process.stdout, 'pipe'], //子進(jìn)程是否獨(dú)立于父進(jìn)程運(yùn)行 detached: false });
1.js的代碼:
console.log('hello');
運(yùn)行代碼后,我們可以看到子進(jìn)程的 'hello',出現(xiàn)在了父進(jìn)程的標(biāo)準(zhǔn)輸出上。因?yàn)?stdio 的配置,我們讓子進(jìn)程與父進(jìn)程共享標(biāo)準(zhǔn)輸出。
spawn() 會(huì)返回一個(gè)子進(jìn)程對(duì)象,我們可以監(jiān)聽該對(duì)象的一些事件。
const {spawn} = require('child_process'); let cp1 = spawn('node', ['1.js'], { cwd: process.cwd(), env: process.env, stdio: ['pipe', process.stdout, 'pipe'], detached: false }); //子進(jìn)程所有輸入/輸出終止時(shí),會(huì)觸發(fā)子進(jìn)程的 'close' 事件 cp1.on('close', function (code, signal) { //當(dāng)父進(jìn)程關(guān)閉子進(jìn)程時(shí),signal表示父進(jìn)程發(fā)送給子進(jìn)程的信號(hào)名稱 console.log('子進(jìn)程關(guān)閉了', code, signal); }); //子進(jìn)程退出時(shí),會(huì)觸發(fā) 'exit' 事件 //注意,子進(jìn)程退出,子進(jìn)程的輸入/輸出有可能并未關(guān)閉。因?yàn)檩斎?輸出有可能多個(gè)進(jìn)程共享。 cp1.on('exit', function (code, signal) { console.log('子進(jìn)程退出', code, signal); }); //子進(jìn)程出錯(cuò)時(shí),觸發(fā) cp1.on('error', function (err) { console.log(err); });
注意,stdio 設(shè)置成 pipe ,是把子進(jìn)程的stdin,stdout,stderr導(dǎo)向了 spawn() 返回的子進(jìn)程對(duì)象的stdin,stdout,stderr。
然后父進(jìn)程就可以通過(guò)子進(jìn)程對(duì)象訪問stdin,stdout,stderr。
const {spawn} = require('child_process'); let cp1 = spawn('node', ['1.js'], { cwd: process.cwd(), env: process.env, stdio: ['pipe', 'pipe', 'pipe'], detached: false }); //監(jiān)聽子進(jìn)程標(biāo)準(zhǔn)輸入,輸出,錯(cuò)誤的數(shù)據(jù)。 cp1.stdin.on('data', function (data) { console.log(data.toString()); }); cp1.stdout.on('data', function (data) { console.log(data.toString()); }); cp1.stderr.on('data', function (data) { console.log(data.toString()); });
1.js的代碼:
//往子進(jìn)程標(biāo)準(zhǔn)輸出中寫入數(shù)據(jù) console.log('我是標(biāo)準(zhǔn)輸出'); //往子進(jìn)程錯(cuò)誤中寫入數(shù)據(jù) console.error('我是一個(gè)錯(cuò)誤'); //往子進(jìn)程標(biāo)準(zhǔn)輸入中寫入數(shù)據(jù) process.stdin.write('我是標(biāo)準(zhǔn)輸入');
當(dāng)我們?cè)O(shè)置 stdio 為 ipc 時(shí),會(huì)創(chuàng)建一個(gè)父進(jìn)程與子進(jìn)程傳遞消息的IPC通道。
const {spawn} = require('child_process'); let cp1 = spawn('node', ['1.js'], { cwd: process.cwd(), env: process.env, //注意這里,子進(jìn)程只能有一個(gè)IPC通道 stdio: ['pipe', 'ipc', 'pipe'], detached: false }); //注意這里要用子進(jìn)程對(duì)象進(jìn)行監(jiān)聽 //監(jiān)聽有沒有消息 cp1.on('message', function (data) { console.log('子進(jìn)程發(fā)送的 : ', data.toString()); }); cp1.send('你好,子進(jìn)程');
1.js的代碼:
process.on('message', function (data) { console.log('父進(jìn)程發(fā)送的 : ', data.toString()); }); //向父進(jìn)程發(fā)送消息 process.send('你好,父進(jìn)程');
默認(rèn)情況下,只有子進(jìn)程全部退出了,父進(jìn)程才能退出。我們希望父進(jìn)程退出了,子進(jìn)程仍然獨(dú)立運(yùn)行??梢酝ㄟ^(guò)設(shè)置 detached 為 true。
默認(rèn)情況下,父進(jìn)程會(huì)等待所有子程退出后,才退出。通過(guò)使用 unref() 讓父進(jìn)程無(wú)需等待子進(jìn)程就可直接退出。
const {spawn} = require('child_process'); const fs = require('fs'); let fd = fs.openSync('./1.txt', 'w', 0o666); let cp1 = spawn('node', ['1.js'], { cwd: process.cwd(), //注意這里,把不需要的設(shè)置為ignore,不然主進(jìn)程仍然會(huì)阻塞等待子進(jìn)程 stdio: ['ignore', fd, 'ignore'], detached: true }); cp1.on('error', function (err) { console.log(err); }); //解綁子進(jìn)程,讓父進(jìn)程不用等待子進(jìn)程 cp1.unref();
1.js的代碼:
let i = 0; let timer = setInterval(function () { if (i > 20) { clearInterval(timer); } process.stdout.write('寫入數(shù)據(jù)' + i + '\r\n'); i++; }, 1000);
2、通過(guò) fork() 創(chuàng)建子進(jìn)程
fork() 是 spawn() 的特殊情況,用于創(chuàng)建新的進(jìn)程,默認(rèn)建立一個(gè)IPC通信通道,允許父進(jìn)程與子進(jìn)程進(jìn)行消息傳遞。
fork() 返回一個(gè)子進(jìn)程對(duì)象,子進(jìn)程輸入/輸出操作執(zhí)行完畢后,父進(jìn)程不退出,子進(jìn)程不會(huì)自動(dòng)退出,需調(diào)用 exit() 顯式退出。
const {fork} = require('child_process'); //參數(shù)一表示,運(yùn)行的模塊 //參數(shù)二表示,參數(shù)列表 //參數(shù)三表示,創(chuàng)建子進(jìn)程的配置 let cp1 = fork('2.js', ['1', '2', '3'], { //子進(jìn)程的工作目錄 cwd: process.cwd(), //子進(jìn)程的環(huán)境變量 env: process.env, //運(yùn)行模塊的可執(zhí)行文件 execPath: process.execPath, //傳遞給可執(zhí)行文件的參數(shù)列表 execArgv: process.execArgv, //為false表示父進(jìn)程與子進(jìn)程共享標(biāo)準(zhǔn)(輸入/輸出),為true時(shí)不共享。 silent: false }); cp1.on('error', function (err) { console.log(err); });
2.js的代碼:
for (let i = 0; i < process.argv.length; i++) { process.stdout.write(process.argv[i] + '\r\n'); }
父進(jìn)程與子進(jìn)程間,通過(guò) send() 和 'message'事件來(lái)傳遞消息。
const {fork} = require('child_process'); let cp1 = fork('2.js', [], { cwd: process.cwd(), env: process.env, silent: false }); //接收消息 cp1.on('message', function (data) { console.log('父進(jìn)程收到 : ', JSON.stringify(data)); process.exit(0); }); //發(fā)送消息 cp1.send({name: '你好子進(jìn)程'});
2.js的代碼:
process.on('message', function (data) { console.log('子進(jìn)程收到 : ', JSON.stringify(data)); process.send({name: '你好父進(jìn)程'}); });
3、通過(guò)exec() 創(chuàng)建子進(jìn)程
exec() 可以開啟一個(gè)子進(jìn)程運(yùn)行命令,并緩存子進(jìn)程的輸出結(jié)果。
const {exec} = require('child_process'); //參數(shù)一表示,要運(yùn)行的命令 //參數(shù)二表示,配置選項(xiàng) //參數(shù)三表示,進(jìn)程終止時(shí)的回調(diào) exec('dir', { //子進(jìn)程的工作目錄 cwd: process.cwd(), //子進(jìn)程的環(huán)境變量 env: process.env, //輸出的編碼 encoding: 'utf8', //超時(shí)時(shí)間 timeout: 60 * 1000, //緩存stdout,stderr最大的字節(jié)數(shù) maxBuffer: 1024 * 1024, //關(guān)閉子進(jìn)程的信號(hào) killSignal: 'SIGTERM' }, function (err, stdout, stderr) { console.log(stdout.toString()); });
4、通過(guò) execFile() 創(chuàng)建子進(jìn)程
使用 execFile() 開啟一個(gè)運(yùn)行可執(zhí)行文件的子進(jìn)程。
const {execFile} = require('child_process'); //參數(shù)一表示,可執(zhí)行文件的名稱或路徑 //參數(shù)二表示,參數(shù)列表 //參數(shù)三表示,配置選項(xiàng) //參數(shù)四表示,進(jìn)程終止時(shí)的回調(diào) let cp1 = execFile('node', ['3.js', '1', '2', '3'], { //子進(jìn)程的工作目錄 cwd: process.cwd(), //子進(jìn)程的環(huán)境變量 env: process.env, //輸出的編碼 encoding: 'utf8', //超時(shí)時(shí)間 timeout: 60 * 1000, //緩存stdout,stderr最大的字節(jié)數(shù) maxBuffer: 1024 * 1024, //關(guān)閉子進(jìn)程的信號(hào) killSignal: 'SIGTERM' }, function (err, stdout, stderr) { if (err) { console.log(err); process.exit(); } console.log('子進(jìn)程的輸出 : ', stdout.toString()); }); cp1.on('error', function (err) { console.log(err); });
3.js的代碼:
process.argv.forEach(function (value) { process.stdout.write(value + '\r\n'); });
fork(),exec(),execFile() 都是基于 spawn() 的封裝。
希望本文所述對(duì)大家node.js程序設(shè)計(jì)有所幫助。
相關(guān)文章
Nodejs文件上傳、監(jiān)聽上傳進(jìn)度的代碼
這篇文章主要介紹了Nodejs文件上傳、監(jiān)聽上傳進(jìn)度,本文通過(guò)實(shí)例代碼給大家詳細(xì)介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03使用ExcelJS快速處理Node.js爬蟲數(shù)據(jù)
Excel.js是一個(gè)強(qiáng)大的JavaScript庫(kù),它提供了方法處理Excel文件,例如創(chuàng)建和編輯工作簿、讀取和寫入數(shù)據(jù)、處理行和列、設(shè)置樣式、導(dǎo)入和導(dǎo)出數(shù)據(jù)等,本文介紹使用ExcelJS快速處理Node.js爬蟲數(shù)據(jù)的方法,一起看看吧2024-01-01Node4-5靜態(tài)資源服務(wù)器實(shí)戰(zhàn)以及優(yōu)化壓縮文件實(shí)例內(nèi)容
這篇文章主要介紹了Node4-5靜態(tài)資源服務(wù)器實(shí)戰(zhàn)以及優(yōu)化壓縮文件實(shí)例內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。2019-08-08詳解阿里Node.js技術(shù)文檔之process模塊學(xué)習(xí)指南
這篇文章主要介紹了詳解阿里Node.js技術(shù)文檔之process模塊學(xué)習(xí)指南,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01nodejs構(gòu)建本地web測(cè)試服務(wù)器 如何解決訪問靜態(tài)資源問題
這篇文章主要為大家詳細(xì)介紹了nodejs構(gòu)建本地web測(cè)試服務(wù)器,教大家如何解決訪問靜態(tài)資源問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Nodejs如何進(jìn)行性能監(jiān)控和分析優(yōu)化
Node.js應(yīng)用可能因?yàn)楦卟l(fā)、內(nèi)存泄漏、CPU密集型任務(wù)等原因?qū)е滦阅芟陆?影響用戶體驗(yàn)甚至系統(tǒng)穩(wěn)定性,通過(guò)性能監(jiān)控和分析,我們可以及時(shí)發(fā)現(xiàn)潛在問題,并針對(duì)性地進(jìn)行優(yōu)化,確保系統(tǒng)正常運(yùn)行且具備良好的性能表現(xiàn)2024-06-06