node.js中process程序的概念和child_process子程序模組的使用方法示例
本文例項講述了node.js中process程序的概念和child_process子程序模組的使用方法。分享給大家供大家參考,具體如下:
程序,你可以把它理解成一個正在執行的程式。node.js中每個應用程式都是程序類的例項物件。
node.js中有一個 process 全域性物件,通過它我們可以獲取,執行該程式的使用者,環境變數等資訊。
一、process 物件
console.log('可執行檔案絕對路徑',process.execPath); console.log('版本號',process.version); console.log('依賴庫的版本號',process.versions); console.log('執行平臺',process.platform); console.log('標準輸入流',process.stdin); console.log('標準輸出流',process.stdout); console.log('標準錯誤流',process.stderr); console.log('命令列引數陣列',process.argv); console.log('系統環境變數',process.env); console.log('程序ID',process.pid); console.log('標題',process.title); console.log('處理器架構',process.arch);
通過 memoryUsage() 檢視記憶體使用量:
console.log(process.memoryUsage());
- rss 表示程序佔用的記憶體,包括堆,棧,程式碼段。
- heapTotal 表示堆佔用的記憶體。
- heapUsed 表示堆使用的部分。
- external 表示外部使用的部分,C++物件佔用的。
物件,字串,閉包存放於堆記憶體,變數存放於棧記憶體,js原始碼存放於程式碼段。
console.log(process.memoryUsage()); let buf = Buffer.alloc(1024 * 1024 * 1024); console.log(process.memoryUsage());
當我們通過Buffer建立一個足夠大的變數時,這時只能藉助於外部記憶體,使用C++去完成。node.js能夠使用的記憶體上限是1.7G。
使用 chdir() 修改程式當前的工作目錄,通過 cwd() 獲取當前工作目錄。
console.log(process.cwd()); //修改程式當前的工作目錄 process.chdir('../'); console.log(process.cwd());
通過 exit() 來結束程序
process.exit(0);
呼叫 exit() 結束程序時,會觸發 'exit' 事件。
process.on('exit',function () { console.log('程式退出了'); }); process.exit(0);
通過 kill() 給指定程序傳送訊號
SIGINT 程式終止訊號,當用戶按下ctrl+c時發出,將通知程序終止。
SIGTERM 程式結束訊號,通知程式正常退出,kill()方法預設就是這個訊號。
process.kill(process.pid,'SIGINT');
通過 uptime() 返回程式執行的時間
console.log(process.uptime());
通過 hrtime() 計算程式碼段執行時間,hrtime() 返回一個數組,第一個表示秒,第二個表示納秒
let start = process.hrtime(); let sum = 0; for (i = 0; i < 1000000000; i++) { sum += i; } let end = process.hrtime(start); console.log('耗時 : ',end[0],'秒');
當程式丟擲一個沒有被捕獲的異常時,觸發 'uncaughtException' 事件。
process.on('uncaughtException',function (err) { console.log('捕獲了一個未被處理的異常'); console.log(err); }); //呼叫一個未定義的函式 test();
程序接收到一個訊號時,會觸發訊號事件,我們可以監聽到該事件。
//讓標準輸入流處於流動模式,讓程式無法退出 process.stdin.resume(); process.on('SIGINT',function () { console.log('程式退出'); process.exit(0); }); process.on('SIGTERM',function () { console.log('程式結束'); });
二、子程序模組child_process的使用
我們都知道node.js是單執行緒的,如果某一個操作需要消耗大量資源和時間,會導致程式整體效能下降。
我們可以建立子程序,讓子程序去跑那些費時費力的操作,而主執行緒該幹嘛幹嘛。
子程序間可以共享記憶體,通過互相通訊來完成資料的交換。
1、通過 spawn() 建立子程序
const {spawn} = require('child_process'); //引數一表示,要執行的命令 //引數二表示,執行該命令的引數 //引數三表示,建立子程序的配置 let cp1 = spawn('node',['1.js'],{ //cwd表示當前子程序的工作目錄 cwd: process.cwd(),//子程序的環境變數 env: process.env,//子程序的標準輸入,標準輸出,錯誤,的配置 //pipe表示,父程序與子程序間建立管道,父程序可以訪問子程序對應的輸入,輸出,和錯誤 //ipc表示,父程序與子程序間建立一個專門用來傳遞訊息的IPC通道,子程序呼叫send()方法向子程序傳送訊息,並觸發'message'事件 //ignore表示,忽略子程序的標準輸入,標準輸出,錯誤。 //inherit表示,子程序共享父程序的標準輸入,標準輸出,錯誤。 //stream表示,父程序與子程序共享一個流,比如檔案流或socket。 //正整數表示,父程序開啟的檔案描述符,與子程序共享,比如檔案的fd。類似stream流物件共享。 //null或undefined表示,父程序與子程序間建立管道 stdio: ['pipe',process.stdout,'pipe'],//子程序是否獨立於父程序執行 detached: false });
1.js的程式碼:
console.log('hello');
執行程式碼後,我們可以看到子程序的 'hello',出現在了父程序的標準輸出上。因為 stdio 的配置,我們讓子程序與父程序共享標準輸出。
spawn() 會返回一個子程序物件,我們可以監聽該物件的一些事件。
const {spawn} = require('child_process'); let cp1 = spawn('node',{ cwd: process.cwd(),env: process.env,stdio: ['pipe',detached: false }); //子程序所有輸入/輸出終止時,會觸發子程序的 'close' 事件 cp1.on('close',function (code,signal) { //當父程序關閉子程序時,signal表示父程序傳送給子程序的訊號名稱 console.log('子程序關閉了',code,signal); }); //子程序退出時,會觸發 'exit' 事件 //注意,子程序退出,子程序的輸入/輸出有可能並未關閉。因為輸入/輸出有可能多個程序共享。 cp1.on('exit',signal) { console.log('子程序退出',signal); }); //子程序出錯時,觸發 cp1.on('error',function (err) { console.log(err); });
注意,stdio 設定成 pipe ,是把子程序的stdin,stdout,stderr導向了 spawn() 返回的子程序物件的stdin,stdout,stderr。
然後父程序就可以通過子程序物件訪問stdin,stdout,stderr。
const {spawn} = require('child_process'); let cp1 = spawn('node','pipe',detached: false }); //監聽子程序標準輸入,輸出,錯誤的資料。 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的程式碼:
//往子程序標準輸出中寫入資料 console.log('我是標準輸出'); //往子程序錯誤中寫入資料 console.error('我是一個錯誤'); //往子程序標準輸入中寫入資料 process.stdin.write('我是標準輸入');
當我們設定 stdio 為 ipc 時,會建立一個父程序與子程序傳遞訊息的IPC通道。
const {spawn} = require('child_process'); let cp1 = spawn('node',//注意這裡,子程序只能有一個IPC通道 stdio: ['pipe','ipc',detached: false }); //注意這裡要用子程序物件進行監聽 //監聽有沒有訊息 cp1.on('message',function (data) { console.log('子程序傳送的 : ',data.toString()); }); cp1.send('你好,子程序');
1.js的程式碼:
process.on('message',function (data) { console.log('父程序傳送的 : ',data.toString()); }); //向父程序傳送訊息 process.send('你好,父程序');
預設情況下,只有子程序全部退出了,父程序才能退出。我們希望父程序退出了,子程序仍然獨立執行。可以通過設定 detached 為 true。
預設情況下,父程序會等待所有子程退出後,才退出。通過使用 unref() 讓父程序無需等待子程序就可直接退出。
const {spawn} = require('child_process'); const fs = require('fs'); let fd = fs.openSync('./1.txt','w',0o666); let cp1 = spawn('node',//注意這裡,把不需要的設定為ignore,不然主程序仍然會阻塞等待子程序 stdio: ['ignore',fd,'ignore'],detached: true }); cp1.on('error',function (err) { console.log(err); }); //解綁子程序,讓父程序不用等待子程序 cp1.unref();
1.js的程式碼:
let i = 0; let timer = setInterval(function () { if (i > 20) { clearInterval(timer); } process.stdout.write('寫入資料' + i + '\r\n'); i++; },1000);
2、通過 fork() 建立子程序
fork() 是 spawn() 的特殊情況,用於建立新的程序,預設建立一個IPC通訊通道,允許父程序與子程序進行訊息傳遞。
fork() 返回一個子程序物件,子程序輸入/輸出操作執行完畢後,父程序不退出,子程序不會自動退出,需呼叫 exit() 顯式退出。
const {fork} = require('child_process'); //引數一表示,執行的模組 //引數二表示,引數列表 //引數三表示,建立子程序的配置 let cp1 = fork('2.js',['1','2','3'],{ //子程序的工作目錄 cwd: process.cwd(),//執行模組的可執行檔案 execPath: process.execPath,//傳遞給可執行檔案的引數列表 execArgv: process.execArgv,//為false表示父程序與子程序共享標準(輸入/輸出),為true時不共享。 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'); }
父程序與子程序間,通過 send() 和 'message'事件來傳遞訊息。
const {fork} = require('child_process'); let cp1 = fork('2.js',[],silent: false }); //接收訊息 cp1.on('message',function (data) { console.log('父程序收到 : ',JSON.stringify(data)); process.exit(0); }); //傳送訊息 cp1.send({name: '你好子程序'});
2.js的程式碼:
process.on('message',function (data) { console.log('子程序收到 : ',JSON.stringify(data)); process.send({name: '你好父程序'}); });
3、通過exec() 建立子程序
exec() 可以開啟一個子程序執行命令,並快取子程序的輸出結果。
const {exec} = require('child_process'); //引數一表示,要執行的命令 //引數二表示,配置選項 //引數三表示,程序終止時的回撥 exec('dir',//輸出的編碼 encoding: 'utf8',//超時時間 timeout: 60 * 1000,//快取stdout,stderr最大的位元組數 maxBuffer: 1024 * 1024,//關閉子程序的訊號 killSignal: 'SIGTERM' },function (err,stdout,stderr) { console.log(stdout.toString()); });
4、通過 execFile() 建立子程序
使用 execFile() 開啟一個執行可執行檔案的子程序。
const {execFile} = require('child_process'); //引數一表示,可執行檔案的名稱或路徑 //引數二表示,引數列表 //引數三表示,配置選項 //引數四表示,程序終止時的回撥 let cp1 = execFile('node',['3.js','1',stderr) { if (err) { console.log(err); process.exit(); } console.log('子程序的輸出 : ',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() 的封裝。
希望本文所述對大家node.js程式設計有所幫助。