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í)例對象。
node.js中有一個(gè) process 全局對象,通過它我們可以獲取,運(yùn)行該程序的用戶,環(huán)境變量等信息。
一、process 對象
console.log('可執(zhí)行文件絕對路徑', process.execPath);
console.log('版本號', process.version);
console.log('依賴庫的版本號', 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);
通過 memoryUsage() 查看內(nèi)存使用量:
console.log(process.memoryUsage());
- rss 表示進(jìn)程占用的內(nèi)存,包括堆,棧,代碼段。
- heapTotal 表示堆占用的內(nèi)存。
- heapUsed 表示堆使用的部分。
- external 表示外部使用的部分,C++對象占用的。
對象,字符串,閉包存放于堆內(nèi)存,變量存放于棧內(nèi)存,js源代碼存放于代碼段。
console.log(process.memoryUsage()); let buf = Buffer.alloc(1024 * 1024 * 1024); console.log(process.memoryUsage());
當(dāng)我們通過Buffer創(chuàng)建一個(gè)足夠大的變量時(shí),這時(shí)只能借助于外部內(nèi)存,使用C++去完成。node.js能夠使用的內(nèi)存上限是1.7G。
使用 chdir() 修改程序當(dāng)前的工作目錄,通過 cwd() 獲取當(dāng)前工作目錄。
console.log(process.cwd());
//修改程序當(dāng)前的工作目錄
process.chdir('../');
console.log(process.cwd());
通過 exit() 來結(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);
通過 kill() 給指定進(jìn)程發(fā)送信號
SIGINT 程序終止信號,當(dāng)用戶按下ctrl+c時(shí)發(fā)出,將通知進(jìn)程終止。
SIGTERM 程序結(jié)束信號,通知程序正常退出,kill()方法默認(rèn)就是這個(gè)信號。
process.kill(process.pid, 'SIGINT');
通過 uptime() 返回程序運(yùn)行的時(shí)間
console.log(process.uptime());
通過 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è)信號時(shí),會(huì)觸發(fā)信號事件,我們可以監(jiān)聽到該事件。
//讓標(biāo)準(zhǔn)輸入流處于流動(dòng)模式,讓程序無法退出
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)存,通過互相通信來完成數(shù)據(jù)的交換。
1、通過 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)程對應(yīng)的輸入,輸出,和錯(cuò)誤
//ipc表示,父進(jìn)程與子進(jìn)程間建立一個(gè)專門用來傳遞消息的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流對象共享。
//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)程對象,我們可以監(jiān)聽該對象的一些事件。
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)程的信號名稱
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)程對象的stdin,stdout,stderr。
然后父進(jìn)程就可以通過子進(jìn)程對象訪問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)我們設(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)程對象進(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)行??梢酝ㄟ^設(shè)置 detached 為 true。
默認(rèn)情況下,父進(jìn)程會(huì)等待所有子程退出后,才退出。通過使用 unref() 讓父進(jìn)程無需等待子進(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、通過 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)程對象,子進(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)程間,通過 send() 和 'message'事件來傳遞消息。
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、通過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)程的信號
killSignal: 'SIGTERM'
}, function (err, stdout, stderr) {
console.log(stdout.toString());
});
4、通過 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)程的信號
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() 的封裝。
希望本文所述對大家node.js程序設(shè)計(jì)有所幫助。
相關(guān)文章
快速掌握Node.js中setTimeout和setInterval的使用方法
這篇文章主要為大家介紹了快速掌握Node.js中setTimeout和setInterval的使用方法,感興趣的小伙伴們可以參考一下2016-03-03
nodejs npm install全局安裝和本地安裝的區(qū)別
這篇文章主要介紹了nodejs npm install 全局安裝和非全局安裝的區(qū)別,即帶參數(shù)-g和不帶參數(shù)-g安裝的區(qū)別,需要的朋友可以參考下2014-06-06
搭建基于express框架運(yùn)行環(huán)境的方法步驟
Express提供了一個(gè)輕量級模塊,把Node.js的http模塊功能封裝在一個(gè)簡單易用的接口中,這篇文章主要介紹了搭建基于express框架運(yùn)行環(huán)境的方法步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11

