1. 程式人生 > 程式設計 >node.js中process程序的概念和child_process子程序模組的使用方法示例

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程式設計有所幫助。