Node.js中的进程

二、课程介绍

这个实验主要学习Node.js中的进程,涉及的模块是Cluster、Porcess和child_process。

Process模块

process模块在前面的实验已经用过了,使用时直接通过全局变量process访问,而不需要通过require方法加载。process用来和当前Node.js程序进程互动。
process是EventEmitter的一个实例,process主要包含<b>退出事件、信号事件以及一些属性</b>。

  • 退出事件(exit)

当退出当前进程时,会促发exit事件,exit事件的回调函数中只接受同步操作,并且回调函数只接受一个参数,即退出代码,如:
<pre>process.on('exit', function(code){
(function() {
console.log('This will not run');
}, 0);
console.log('exit code: ', code);
});
</pre>
运行上面的代码,其中setTimeout方法中的回调函数是不会被执行的,因为exit事件中只会运行同步操作,而不会运行异步操作。
在exit事件之前还有一个beforeExit事件会被触发,在beforeExit的回调函数中可以执行异步操作。值得注意的是,通过process.exit()退出程序或者因为发生错误而退出程序是不会触发beforeExit事件的。顺便说一下,当有错误未被捕获时,就会<b>触发uncaughtException事件</b>。

  • 信号事件

信号事件就是接收到某个特定信号才会被触发的事件。
比如SIGINT事件的触发方式是ctrl+c:
<pre>
// sigint.js
process.stdin.resume();
process.on('SIGINT', function() {
console.log('Got SIGINT. Press Control-D to exit.');
});
</pre>
运行代码:<pre>$ node sigint.js</pre>
然后按住control键,再按C键就会触发SIGINT事件。

属性

 process模块提供了很多属性,其中关于IO输入输出的主要有三个:
 process.stdin  // 标准输入
 process.stdout // 标准输出
 process.stderr // 标准错误

举例:
<pre>
// stdin.js
process.stdin.setEncoding('utf8');
process.stdin.on('readable', function() {
var chunk = process.stdin.read();
if (chunk !== null) {
process.stdout.write('data: ' + chunk);
}
});
process.stdin.on('end', function() {
process.stdout.write('end');
});
</pre>
运行:<pre>node stdin.js</pre>

输入任意字符,Node.js会把输入的字符打印出来,输入ctrl+D触发end事件。

还有其他属性,比如process.argv是一个包含了命令行参数的数组。
方法

process模块还有很多实用的方法,比如:
process.cwd() // 返回脚本运行工作目录
process.chdir() // 切换工作目录
process.exit() // 退出当前进程
process.on() // 添加监听事件
//...


child_process模块

child_process用于创建子进程。
child_process.spawn()方法

通过当前命令启动一个新的进程。如:
<pre>
// test_spawn.js
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});
</pre>
运行命令:
<pre>$ node test_spawn.js</pre>
从结果可以看出,子进程成功运行了ls -lh /usr命令。
child_process.exec()方法

在shell中运行一个命令,并缓存其输出。如:
<pre>
// test_exec.js
var exec = require('child_process').exec,
child;
child = exec('cat *.js bad_file | wc -l',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
</pre>
运行:
<pre>$ node test_exec.js</pre>
因为没有bad_file 这个文件,所以会看到终端打印出了相关错误信息。

child_process.execFile()方法

与exec方法类似,执行特定程序文件,参数通过一个数组传送。,如:
<pre>
// test_execfile.js
var child_process = require('child_process');
// exec: spawns a shell
child_process.exec('ls -lh /usr', function(error, stdout, stderr){
console.log(stdout);
console.log('******************');
});
// execFile: executes a file with the specified arguments
child_process.execFile('/bin/ls', ['-lh', '/usr'], function(error, stdout, stderr){
console.log(stdout);
});
</pre>
运行:
<pre>$ node test_execfile.js</pre>
#######child_process.fork()方法

直接创建一个子进程,此进程是node命令的子进程,fork('./sub.js')相当于spwan('node', './sub.js')。fork还会在父进程与子进程之间,建立一个通信管道,通过child.send()发送消息。如:
<pre>
// main.js
var cp = require('child_process');
var n = cp.fork(__dirname + '/sub.js');
n.on('message', function(m) {
console.log('PARENT got message:', m);
});
n.send({ hello: 'world' });
// sub.js
process.on('message', function(m) {
console.log('CHILD got message:', m);
});
process.send({ foo: 'bar' });
</pre>
运行:
<pre>$ node main.js</pre>
运行main.js会看到主进程收到了来自子进程的消息,而子进程也收到了来自主进程的消息。

cluster模块

单个的Node实例运行在单个线程中。要发挥多核系统的能力,需要启动一个Node进程集群来处理负载。cluster模块就用于创建共享服务器端口的子进程。
<pre>
// test_cluster.js
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length; // 获取CPU内核数
// master是主进程
// 此处判断是否为master进程
// 是则根据CPU内核数创建worker进程
if (cluster.isMaster) {
// worker是运行节点
// 根据CPU数量启动worker
// Fork workers
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log('I am running with ID : ' + cluster.workers[id].process.pid);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
// cluster.isWorker == true
// 运行到else中的代码
// 说明当前进程是worker进程
// 那么此worker进程就启动一个http服务
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
</pre>
运行程序:
<pre>$ node test_cluster.js</pre>

在终端会看到根据CPU内核数创建的子进程信息。

每个worker进程都是通过child_process.fork()方法产生的,所以它们可以通过IPC(进程间通信)与master进程通信。

cluster.worker是worker进程对象,其中有 worker.id、worker.process等属性,还有worker.send()等方法。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容