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框架中处理404页面一个方式
May 28 NodeJs
Nodejs学习笔记之测试驱动
Apr 16 NodeJs
nodeJS删除文件方法示例
Dec 25 NodeJs
Ajax异步文件上传与NodeJS express服务端处理
Apr 01 NodeJs
NodeJS、NPM安装配置步骤(windows版本) 以及环境变量详解
May 13 NodeJs
详解HTTPS 的原理和 NodeJS 的实现
Jul 04 NodeJs
nodejs 图解express+supervisor+ejs的用法(推荐)
Sep 08 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
详解redis在nodejs中的应用
May 02 NodeJs
详解Nodejs get获取远程服务器接口数据
Mar 26 NodeJs
Nodejs使用archiver-zip-encrypted库加密压缩文件时报错(解决方案)
Nov 18 NodeJs
Nodejs封装类似express框架的路由实例详解
Jan 05 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实现模拟http请求的方法分析
2017/12/20 PHP
php获取是星期几的的一些常用姿势
2019/12/15 PHP
Laravel登录失败次数限制的实现方法
2020/08/26 PHP
BOOM vs RR BO3 第二场2.13
2021/03/10 DOTA
Jquery实现仿新浪微博获取文本框能输入的字数代码
2013/02/22 Javascript
js定时器怎么写?就是在特定时间执行某段程序
2013/10/11 Javascript
js设置文本框中焦点位置在最后的示例代码(简单实用)
2014/03/04 Javascript
Nodejs进程管理模块forever详解
2014/06/01 NodeJs
Javascript中实现trim()函数的两种方法
2015/02/04 Javascript
深入浅出分析javaScript中this用法
2015/05/09 Javascript
js限制文本框的输入内容代码分享(3类)
2015/08/20 Javascript
JavaScript实现搜索框的自动完成功能(一)
2016/02/25 Javascript
JS 清除字符串数组中,重复元素的实现方法
2016/05/24 Javascript
EasyUI创建对话框的两种方式
2016/08/23 Javascript
js正则表达式注册页面表单验证
2016/10/11 Javascript
Angular ui.bootstrap.pagination分页
2017/01/20 Javascript
Angularjs 动态添加指令并绑定事件的方法
2017/04/13 Javascript
Javascript实现基本运算器
2017/07/15 Javascript
详解利用 Express 托管静态文件的方法
2017/09/18 Javascript
利用jquery如何从json中读取数据追加到html中
2017/12/01 jQuery
js实现橱窗展示效果
2020/01/11 Javascript
element-ui树形控件后台返回的数据+生成组织树的工具类
2020/03/05 Javascript
在实例中重学JavaScript事件循环
2020/12/03 Javascript
[02:35]DOTA2超级联赛专访XB 难忘一年九冠称王
2013/06/20 DOTA
Python MD5文件生成码
2009/01/12 Python
python读取html中指定元素生成excle文件示例
2014/04/03 Python
举例讲解Python设计模式编程的代理模式与抽象工厂模式
2016/01/16 Python
python多进程和多线程究竟谁更快(详解)
2017/05/29 Python
Python多线程原理与用法实例剖析
2019/01/22 Python
详解python logging日志传输
2020/07/01 Python
Django日志及中间件模块应用案例
2020/09/10 Python
python实现sm2和sm4国密(国家商用密码)算法的示例
2020/09/26 Python
舞会礼服和舞会鞋:PromGirl
2019/04/22 全球购物
农业局学习党的群众路线教育实践活动心得体会
2014/03/07 职场文书
代理人委托书
2014/09/16 职场文书
PostGIS的安装与入门使用指南
2022/01/18 PostgreSQL