Nodejs极简入门教程(三):进程


Posted in NodeJs onOctober 27, 2014

Node 虽然自身存在多个线程,但是运行在 v8 上的 JavaScript 是单线程的。Node 的 child_process 模块用于创建子进程,我们可以通过子进程充分利用 CPU。范例:

var fork = require('child_process').fork;

// 获取当前机器的 CPU 数量

var cpus = require('os').cpus();

for (var i = 0; i < cpus.length; i++) {

    // 生成新进程

    fork('./worker.js');

}

这里了解一下包括 fork 在内的几个进程创建方法:

1.spawn(command, [args], [options]),启动一个新进程来执行命令 command,args 为命令行参数
2.exec(command, [options], callback),启动一个新进程来执行命令 command,callback 用于在进程结束时获取标准输入、标准输出,以及错误信息
3.execFile(file, [args], [options], [callback]),启动一个新进程来执行可执行文件 file,callback 用于在进程结束时获取标准输入、标准输出,以及错误信息
4.fork(modulePath, [args], [options]),启动一个新进程来执行一个 JavaScript 文件模块,这时候创建的是 Node 子进程

Node 进程间通信

父进程

// parent.js

var fork = require('child_process').fork;

// fork 返回子进程对象 n

var n = fork('./child.js');

// 处理事件 message

n.on('message', function(m) {

    // 收到子进程发送的消息

    console.log('got message: ' + m);

});

 

// 向子进程发送消息

n.send({hello: 'world'});

子进程

// child.js

// 处理事件 message

process.on('message', function(m) {

    console.log('got message: ' + m);

});

 

// process 存在 send 方法,用于向父进程发送消息

process.send({foo: 'bar'});

需要注意的是,这里的 send 方法是同步的,因此不建议用于发送大量的数据(可以使用 pipe 来代替,详细见:http://nodejs.org/api/all.html#child_process_child_process_spawn_command_args_options)。
特殊的情况,消息中 cmd 属性值包含 NODE_ 前缀(例如:{cmd: ‘NODE_foo'} 消息),那么此消息不会被提交到 message 事件(而是 internalMessage 事件),它们被 Node 内部使用。

send 方法的原型为:

send(message, [sendHandle])

这里,sendHandle(handle)可以被用于发送:

1.net.Native,原生的 C++ TCP socket 或者管道
2.net.Server,TCP 服务器
3.net.Socket,TCP socket
4.dgram.Native,原生的 C++ UDP socket
5.dgram.Socket,UDP socket

send 发送 sendHandle 时实际上不是(也不能)直接发送 JavaScript 对象,而是发送文件描述符(最终以 JSON 字符串发送),其他进程能够通过这个文件描述符还原出对应对象。

现在看一个例子:

父进程

// parent.js

var fork = require('child_process').fork;

 

var n = fork('./child.js');

 

var server = require('net').createServer();

server.listen(7000, function() {

    // 发送 TCP server 到子进程

    n.send('server', server);

}).on('connection', function() {

    console.log('connection - parent');

});

子进程

process.on('message', function(m, h) {

    if (m === 'server') {

        h.on('connection', function() {

            console.log('connection - child');

        });

    }

});

通过端口 7000 访问此程序,得到输出可能为 connection ? parent 也可能得到输出 connection ? child。这里子进程和父进程同时监听了端口 7000。通常来说,多个进程监听同一个端口会引起 EADDRINUSE 的异常,而此例的情况是,不同的两个进程使用了相同的文件描述符,且 Node 底层在监听端口时对 socket 设置了 SO_REUSEADDR 选项,这使得此 socket 可以在不同的进程间复用。在多个进程监听同一个端口时,同一时刻文件描述符只能被一个进程使用,这些进程对 socket 的使用是抢占式的。

cluster 模块

在 Node 的 v0.8 新增了 cluster 模块,通过 cluster 模块能够轻松的在一台物理机器上构建一组监听相同端口的进程。范例:

var cluster = require('cluster');

var http = require('http');

var numCPUs = require('os').cpus().length;

 

// 检查进程是否是 master 进程

if (cluster.isMaster) {

    for (var i = 0; i < numCPUs; ++i)

        // 生成新的 worker 进程(只有 master 进程才可以调用)

        cluster.fork();

 

    cluster.on('exit', function(worker, code, signal) {

        console.log('worker ' + worker.process.pid + ' died');

    });

} else {

    http.createServer(function(req, res) {

        res.writeHead(200);

        res.end('hello world\n');

    }).listen(8000);

}

我们在 worker 进程中调用 listen 方法,监听请求将会传递给 master 进程。如果 master 进程已经存在一个正在监听的 server 符合 worker 进程的要求,那么此 server 的 handle 将会传递给 worker,如果不存在,master 进程则会创建一个,然后将 handle 传递给 worker 进程。

更多详细的关于 cluster 的文档:http://www.nodejs.org/api/cluster.html

NodeJs 相关文章推荐
nodejs教程 安装express及配置app.js文件的详细步骤
May 11 NodeJs
nodejs教程之异步I/O
Nov 21 NodeJs
轻松创建nodejs服务器(10):处理上传图片
Dec 18 NodeJs
NodeJS学习笔记之Http模块
Jan 13 NodeJs
浅析nodejs实现Websocket的数据接收与发送
Nov 19 NodeJs
详解nodejs 文本操作模块-fs模块(三)
Dec 22 NodeJs
nodejs之koa2请求示例(GET,POST)
Aug 07 NodeJs
nodejs aes 加解密实例
Oct 10 NodeJs
nodejs分离html文件里面的js和css的方法
Apr 09 NodeJs
nodejs中实现修改用户路由功能
May 24 NodeJs
纯异步nodejs文件夹(目录)复制功能
Sep 03 NodeJs
详解NodeJs项目 CentOs linux服务器线上部署
Sep 16 NodeJs
Nodejs极简入门教程(二):定时器
Oct 25 #NodeJs
Nodejs极简入门教程(一):模块机制
Oct 25 #NodeJs
基于NodeJS的前后端分离的思考与实践(六)Nginx + Node.js + Java 的软件栈部署实践
Sep 26 #NodeJs
基于NodeJS的前后端分离的思考与实践(五)多终端适配
Sep 26 #NodeJs
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
Sep 26 #NodeJs
基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架
Sep 26 #NodeJs
基于NodeJS的前后端分离的思考与实践(二)模版探索
Sep 26 #NodeJs
You might like
php4的session功能评述(二)
2006/10/09 PHP
怎么样可以把 phpinfo()屏蔽掉?
2006/11/24 PHP
php递归实现无限分类生成下拉列表的函数
2010/08/08 PHP
详解PHP执行定时任务的实现思路
2015/12/21 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
php+ajax 文件上传代码实例
2019/03/18 PHP
jQuery Div中加载其他页面的实现代码
2009/02/27 Javascript
Javascript 函数对象的多重身份
2009/06/28 Javascript
用 Javascript 验证表单(form)中的单选(radio)值
2009/09/08 Javascript
javascript 弹出层组件(升级版)
2011/05/12 Javascript
js匿名函数的调用示例(形式多种多样)
2014/08/20 Javascript
JavaScript中的return语句简单介绍
2015/12/07 Javascript
node.js实现爬虫教程
2020/08/25 Javascript
Node.js的项目构建工具Grunt的安装与配置教程
2016/05/12 Javascript
jQuery中layer分页器的使用
2017/03/13 Javascript
javascript数组拍平方法总结
2018/01/20 Javascript
解决使用Vue.js显示数据的时,页面闪现原始代码的问题
2018/02/11 Javascript
关于vue-cli3打包代码后白屏的解决方案
2020/09/02 Javascript
[45:56]Ti4正赛第一天 VG vs NEWBEE 3
2014/07/19 DOTA
[07:43]《辉夜杯》公开赛晋级外卡赛战队—TRG训练生活探秘
2015/12/11 DOTA
[43:57]LGD vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python使用在线API查询IP对应的地理位置信息实例
2014/06/01 Python
Python操作MySQL简单实现方法
2015/01/26 Python
python文件写入write()的操作
2019/05/14 Python
python解析yaml文件过程详解
2019/08/30 Python
python打印n位数“水仙花数”(实例代码)
2019/12/25 Python
Python random模块制作简易的四位数验证码
2020/02/01 Python
Python更新所有已安装包的操作
2020/02/13 Python
表单button的outline在firefox浏览器下的问题
2012/12/24 HTML / CSS
Canvas 帧动画吃苹果小游戏
2020/08/05 HTML / CSS
5.12护士节演讲稿
2014/04/30 职场文书
公安交警个人对照检查材料思想汇报
2014/10/01 职场文书
入党函调证明材料
2015/06/19 职场文书
听证会主持词
2015/07/03 职场文书
2015年度女工工作总结
2015/10/22 职场文书
接触艺术对孩子学习思维有益
2019/08/06 职场文书