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 相关文章推荐
golang、python、php、c++、c、java、Nodejs性能对比
Mar 12 NodeJs
nodejs npm package.json中文文档
Sep 04 NodeJs
nodejs爬虫抓取数据乱码问题总结
Jul 03 NodeJs
Nodejs实现短信验证码功能
Feb 09 NodeJs
深入nodejs中流(stream)的理解
Mar 27 NodeJs
手把手教你把nodejs部署到linux上跑出hello world
Jun 19 NodeJs
nodejs实现超简单生成二维码的方法
Mar 17 NodeJs
nodejs基础之常用工具模块util用法分析
Dec 26 NodeJs
nodejs搭建本地服务器并访问文件操作示例
May 11 NodeJs
NodeJs 实现简单WebSocket即时通讯的示例代码
Aug 05 NodeJs
Nodejs监控事件循环异常示例详解
Sep 22 NodeJs
Nodejs文件上传、监听上传进度的代码
Mar 27 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
PHP中Date获取时间不正确怎么办
2008/06/05 PHP
php中通过数组进行高效随机抽取指定条记录的算法
2013/09/09 PHP
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
ThinkPHP、ZF2、Yaf、Laravel框架路由大比拼
2015/03/25 PHP
yii使用bootstrap分页样式的实例
2017/01/17 PHP
一些主流JS框架中DOMReady事件的实现小结
2011/02/12 Javascript
javascript的渐进增强与平稳退化浅谈
2013/11/12 Javascript
一个JavaScript防止表单重复提交的实例
2014/10/21 Javascript
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
js实现点击图片改变页面背景图的方法
2015/02/28 Javascript
JavaScript使用Max函数返回两个数字中较大数的方法
2015/04/06 Javascript
浅谈JavaScript的闭包函数
2016/12/08 Javascript
Node.js实现注册邮箱激活功能的方法示例
2018/03/23 Javascript
postman+json+springmvc测试批量添加实例
2018/03/31 Javascript
Element输入框带历史查询记录的实现示例
2019/01/15 Javascript
微信小程序实现文件、图片上传功能
2020/08/18 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
vue 返回上一页,页面样式错乱的解决
2019/11/14 Javascript
《javascript设计模式》学习笔记四:Javascript面向对象程序设计链式调用实例分析
2020/04/07 Javascript
[01:43]倾听DOTA2英雄之声 魅惑魔女国服配音鉴赏
2013/06/06 DOTA
[46:43]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第三局
2016/02/28 DOTA
[01:01:01]完美世界DOTA2联赛循环赛 GXR vs FTD BO2第一场 10.29
2020/10/29 DOTA
Python多线程编程(四):使用Lock互斥锁
2015/04/05 Python
python的else子句使用指南
2016/02/27 Python
Python基于whois模块简单识别网站域名及所有者的方法
2018/04/23 Python
numpy 进行数组拼接,分别在行和列上合并的实例
2018/05/08 Python
Django网络框架之创建虚拟开发环境操作示例
2019/06/06 Python
Python实现将蓝底照片转化为白底照片功能完整实例
2019/12/13 Python
德国最大的设计师鞋网上商店:Budapester
2017/12/07 全球购物
FC-Moto英国:欧洲最大的摩托车服装和头盔商店之一
2019/08/25 全球购物
心理学专业毕业生推荐信范文
2013/11/21 职场文书
大学共青团员个人自我评价
2014/04/16 职场文书
环保专项行动方案
2014/05/12 职场文书
幼儿园托班开学寄语(2016春季)
2015/12/03 职场文书
RestTemplate如何通过HTTP Basic Auth认证示例说明
2022/03/17 Java/Android
豆瓣2021评分最高动画剧集-豆瓣评分最高的动画剧集2021
2022/03/18 日漫