天天看點

iis worker process記憶體占用大_Nodejs入門:process子產品

iis worker process記憶體占用大_Nodejs入門:process子產品

子產品概覽

process是node的全局子產品,作用比較直覺。可以通過它來獲得node程序相關的資訊,比如運作node程式時的指令行參數。或者設定程序相關資訊,比如設定環境變量。

環境變量:process.env

使用頻率很高,node服務運作時,時常會判斷目前服務運作的環境,如下所示

if(process.env.NODE_ENV === 'production'){
    console.log('生産環境');
}else{
    console.log('非生産環境');
}
           

運作指令

NODE_ENV=production node env.js

,輸出如下

非生産環境
           

異步:process.nextTick(fn)

使用頻率同樣很高,通常用在異步的場景,來個簡單的栗子:

console.log('海賊王');
process.nextTick(function(){
    console.log('火影忍者');
});
console.log('死神');

// 輸出如下
// 海賊王
// 死神
// 火影忍者
           

process.nextTick(fn) 咋看跟 setTimeout(fn, 0) 很像,但實際有實作及性能上的差異,我們先記住幾個點:

  • process.nextTick(fn) 将 fn 放到 node 事件循環的 下一個tick 裡;
  • process.nextTick(fn) 比 setTimetout(fn, 0) 性能高;

這裡不打算深入讨論,感興趣的可以點選這裡進行了解。

擷取指令行參數:process.argv

process.argv 傳回一個數組,數組元素分别如下:

  • 元素1:node
  • 元素2:可執行檔案的絕對路徑
  • 元素x:其他,比如參數等
// print process.argv
process.argv.forEach(function(val, index, array) {
  console.log('參數' + index + ': ' + val);
});
           

運作指令

NODE_ENV=dev node argv.js --env production

,輸出如下。(不包含環境變量)

參數0: /Users/a/.nvm/versions/node/v6.1.0/bin/node
參數1: /Users/a/Documents/git-code/nodejs-learning-guide/examples/2016.11.22-node-process/argv.js
參數2: --env
參數3: production
           

擷取node specific參數:process.execArgv

跟 process.argv 看着像,但差異很大。它會傳回 node specific 的參數(也就是運作node程式特有的參數啦,比如 --harmony)。這部分參數不會出現在 process.argv 裡。

我們來看個例子,相當直覺。輸入指令

node --harmony execArgv.js --nick chyingp

, execArgv.js 代碼如下:

process.execArgv.forEach(function(val, index, array) {
  console.log(index + ': ' + val);
});
// 輸出:
// 0: --harmony

process.argv.forEach(function(val, index, array) {
  console.log(index + ': ' + val);
});
// 輸出:
// 0: /Users/a/.nvm/versions/node/v6.1.0/bin/node
// 1: /Users/a/Documents/git-code/nodejs-learning-guide/examples/2016.11.22-node-process/execArgv.js
// 2: --nick
// 3: chyingp
           

目前工作路徑:process.cwd() vs process.chdir(directory)

  • process.cwd():傳回目前工作路徑
  • process.chdir(directory):切換目前工作路徑

工作路徑的用途不用過多解釋了,直接上代碼

console.log('Starting directory: ' + process.cwd());
try {
  process.chdir('/tmp');
  console.log('New directory: ' + process.cwd());
}
catch (err) {
  console.log('chdir: ' + err);
}
           

輸出如下:

Starting directory: /Users/a/Documents/git-code/nodejs-learning-guide/examples/2016.11.22-node-process
New directory: /private/tmp
           

IPC相關

  • process.connected:如果目前程序是子程序,且與父程序之間通過IPC通道連接配接着,則為true;
  • process.disconnect():斷開與父程序之間的IPC通道,此時會将 process.connected 置為false;

首先是 connected.js,通過 fork 建立子程序(父子程序之間建立了IPC通道)

var child_process = require('child_process');

child_process.fork('./connectedChild.js', {
  stdio: 'inherit'
});
           

然後,在 connectedChild.js 裡面。

console.log( 'process.connected: ' + process.connected );
process.disconnect();
console.log( 'process.connected: ' + process.connected );

// 輸出:
// process.connected: true
// process.connected: false
           

其他

process.config:跟node的編譯配置參數有關

标準輸入/标準輸出/标準錯誤輸出:process.stdin、process.stdout

process.stdin、process.stdout、process.stderr 分别代表程序的标準輸入、标準輸出、标準錯誤輸出。看官網的例子

process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write(`data: ${chunk}`);
  }
});

process.stdin.on('end', () => {
  process.stdout.write('end');
});
           

執行程式,可以看到,程式通過 process.stdin 讀取使用者輸入的同時,通過 process.stdout 将内容輸出到控制台

hello
data: hello
world
data: world
           

process.stderr也差不多,讀者可以自己試下。

使用者組/使用者 相關

process.seteuid(id): process.geteuid():獲得目前使用者的id。(POSIX平台上才有效)

process.getgid(id) process.getgid():獲得目前群組的id。(POSIX平台上才有效,群組、有效群組 的差別,請自行谷歌)

process.setegid(id) process.getegid():獲得目前有效群組的id。(POSIX平台上才有效)

process.setroups(groups): process.getgroups():獲得附加群組的id。(POSIX平台上才有效,

process.setgroups(groups): process.setgroups(groups):

process.initgroups(user, extra_group):

目前程序資訊

  • process.pid:傳回程序id。
  • process.title:可以用它來修改程序的名字,當你用

    ps

    指令,同時有多個node程序在跑的時候,作用就出來了。

運作情況/資源占用情況

  • process.uptime():目前node程序已經運作了多長時間(機關是秒)。
  • process.memoryUsage():傳回程序占用的記憶體,機關為位元組。輸出内容大緻如下:
{ 
    rss: 19181568, 
    heapTotal: 8384512, // V8占用的内容
    heapUsed: 4218408 // V8實際使用了的記憶體
}
           
  • process.cpuUsage([previousValue]):CPU使用時間耗時,機關為毫秒。user表示使用者程式代碼運作占用的時間,system表示系統占用時間。如果目前程序占用多個核心來執行任務,那麼數值會比實際感覺的要大。官方例子如下:
const startUsage = process.cpuUsage();
// { user: 38579, system: 6986 }

// spin the CPU for 500 milliseconds
const now = Date.now();
while (Date.now() - now < 500);

console.log(process.cpuUsage(startUsage));
// { user: 514883, system: 11226 }
           
  • process.hrtime():一般用于做性能基準測試。傳回一個數組,數組裡的值為 [[seconds, nanoseconds] (1秒等10的九次方毫微秒)。 注意,這裡傳回的值,是相對于過去一個随機的時間,是以本身沒什麼意義。僅當你将上一次調用傳回的值做為參數傳入,才有實際意義。

把官網的例子稍做修改:

var time = process.hrtime();

setInterval(() => {
  var diff = process.hrtime(time);

  console.log(`Benchmark took ${diff[0] * 1e9 + diff[1]} nanoseconds`);
}, 1000);
           

輸出大概如下:

Benchmark took 1006117293 nanoseconds
Benchmark took 2049182207 nanoseconds
Benchmark took 3052562935 nanoseconds
Benchmark took 4053410161 nanoseconds
Benchmark took 5056050224 nanoseconds
           

node可執行程式相關資訊

  1. process.version:傳回目前node的版本,比如'v6.1.0'。
  2. process.versions:傳回node的版本,以及依賴庫的版本,如下所示。
{ http_parser: '2.7.0',
  node: '6.1.0',
  v8: '5.0.71.35',
  uv: '1.9.0',
  zlib: '1.2.8',
  ares: '1.10.1-DEV',
  icu: '56.1',
  modules: '48',
  openssl: '1.0.2h' }
           
  1. process.release:傳回目前node發行版本的相關資訊,大部分時候不會用到。具體字段含義可以看這裡。
{
  name: 'node',
  lts: 'Argon',
  sourceUrl: 'https://nodejs.org/download/release/v4.4.5/node-v4.4.5.tar.gz',
  headersUrl: 'https://nodejs.org/download/release/v4.4.5/node-v4.4.5-headers.tar.gz',
  libUrl: 'https://nodejs.org/download/release/v4.4.5/win-x64/node.lib'
}
           
  1. process.config:傳回目前 node版本 編譯時的參數,同樣很少會用到,一般用來查問題。
  2. process.execPath:node可執行程式的絕對路徑,比如 '/usr/local/bin/node'

程序運作所在環境

  • process.arch:傳回目前系統的處理器架構(字元串),比如'arm', 'ia32', or 'x64'。
  • process.platform:傳回關于平台描述的字元串,比如 darwin、win32 等。

警告資訊:process.emitWarning(warning);

v6.0.0新增的接口,可以用來抛出警告資訊。最簡單的例子如下,隻有警告資訊

process.emitWarning('Something happened!');
// (node:50215) Warning: Something happened!
           

可以給警告資訊加個名字,便于分類

process.emitWarning('Something Happened!', 'CustomWarning');
// (node:50252) CustomWarning: Something Happened!
           

可以對其進行監聽

process.emitWarning('Something Happened!', 'CustomWarning');

process.on('warning', (warning) => {
  console.warn(warning.name);
  console.warn(warning.message);
  console.warn(warning.stack);
});

/*
(node:50314) CustomWarning: Something Happened!
CustomWarning
Something Happened!
CustomWarning: Something Happened!
    at Object.<anonymous> (/Users/a/Documents/git-code/nodejs-learning-guide/examples/2016.11.22-node-process/emitWarning.js:3:9)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:456:32)
    at tryModuleLoad (module.js:415:12)
    at Function.Module._load (module.js:407:3)
    at Function.Module.runMain (module.js:575:10)
    at startup (node.js:160:18)
    at node.js:445:3
*/
           

也可以直接給個Error對象

const myWarning = new Error('Warning! Something happened!');
myWarning.name = 'CustomWarning';

process.emitWarning(myWarning);
           

向程序發送信号:process.kill(pid, signal)

process.kill() 這個方法名可能會讓初學者感到困惑,其實它并不是用來殺死程序的,而是用來向程序發送信号。舉個例子:

console.log('hello');

process.kill(process.pid, 'SIGHUP');

console.log('world');
           

輸出如下,可以看到,最後一行代碼并沒有執行,因為向目前程序發送 SIGHUP 信号,程序退出所緻。

hello
[1]    50856 hangup     node kill.js
           

可以通過監聽 SIGHUP 事件,來阻止它的預設行為。

process.on('SIGHUP', () => {
  console.log('Got SIGHUP signal.');
});

console.log('hello');

process.kill(process.pid, 'SIGHUP');

console.log('world');
           

測試結果比較意外,輸出如下:(osx 10.11.4),SIGHUP 事件回調裡的内容并沒有輸出。

hello
world
           

猜測是因為寫标準輸出被推到下一個事件循環導緻(類似process.exit()小節提到的),再試下

process.on('SIGHUP', () => {
  console.log('Got SIGHUP signal.');
});

setTimeout(function(){
  console.log('Exiting.');
}, 0);

console.log('hello');

process.kill(process.pid, 'SIGHUP');

console.log('world');
           

輸出如下(其實并不能說明什麼。。。知道真相的朋友請舉手。。。)

hello
world
Exiting.
Got SIGHUP signal.
           

終止程序:process.exit([exitCode])、process.exitCode

  1. process.exit([exitCode]) 可以用來立即退出程序。即使目前有操作沒執行完,比如 process.exit() 的代碼邏輯,或者未完成的異步邏輯。
  2. 寫資料到 process.stdout 之後,立即調用 process.exit() 是不保險的,因為在node裡面,往 stdout 寫資料是非阻塞的,可以跨越多個事件循環。于是,可能寫到一半就跪了。比較保險的做法是,通過process.exitCode設定退出碼,然後等程序自動退出。
  3. 如果程式出現異常,必須退出不可,那麼,可以抛出一個未被捕獲的error,來終止程序,這個比 process.exit() 安全。

來段官網的例子鎮樓:

// How to properly set the exit code while letting
// the process exit gracefully.
if (someConditionNotMet()) {
  printUsageToStdout();
  process.exitCode = 1;
}
           

備注:整個 process.exit() 的接口說明,都在告訴我們 process.exit() 這個接口有多不可靠。。。還用嗎。。。

事件

  • beforeExit:程序退出之前觸發,參數為 exitCode。(此時eventLoop已經空了)如果是顯式調用 process.exit()退出,或者未捕獲的異常導緻退出,那麼 beforeExit 不會觸發。(我要,這事件有何用。。。)
  • exit:

相關連結

Understanding process.nextTick()

nodejs 異步之 Timer &Tick; 篇