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入门详解(多篇文章结合)
Mar 07 NodeJs
Nodejs中自定义事件实例
Jun 20 NodeJs
轻松创建nodejs服务器(7):阻塞操作的实现
Dec 18 NodeJs
NodeJS创建基础应用并应用模板引擎
Apr 12 NodeJs
详解nodejs的express如何自动生成项目框架
Jul 12 NodeJs
nodejs前端自动化构建环境的搭建
Jul 26 NodeJs
使用npm安装最新版本nodejs
Jan 18 NodeJs
Nodejs把接收图片base64格式保存为文件存储到服务器上
Sep 26 NodeJs
基于Koa(nodejs框架)对json文件进行增删改查的示例代码
Feb 02 NodeJs
nodejs的安装使用与npm的介绍
Sep 11 NodeJs
nodejs中使用archive压缩文件的实现代码
Nov 26 NodeJs
Nodejs + sequelize 实现增删改查操作
Nov 07 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
理解PHP5中static和const关键字的区别
2007/03/19 PHP
40个迹象表明你还是PHP菜鸟
2008/09/29 PHP
PHP实现今天是星期几的几种写法
2013/09/26 PHP
PHP中使用file_get_contents抓取网页中文乱码问题解决方法
2014/12/17 PHP
PHP实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
PHP引用的调用方法分析
2016/04/25 PHP
在 PHP 和 Laravel 中使用 Traits的方法
2019/11/13 PHP
ExtJS 2.0实用简明教程之应用ExtJS
2009/04/29 Javascript
php上传图片并给图片打上透明水印的代码
2010/06/07 Javascript
js获取GridView中行数据的两种方法 分享
2013/07/13 Javascript
jquery如何获取元素的滚动条高度等实现代码
2015/10/19 Javascript
关于Vue.js一些问题和思考学习笔记(2)
2016/12/02 Javascript
Vue.js实现一个SPA登录页面的过程【推荐】
2017/04/29 Javascript
详解webpack es6 to es5支持配置
2017/05/04 Javascript
jquery实现企业定位式导航效果
2018/01/01 jQuery
JS实现统计字符串中字符出现个数及最大个数功能示例
2018/06/04 Javascript
jquery实现搜索框功能实例详解
2018/07/23 jQuery
用图片替换checkbox原始样式并实现同样的功能
2018/11/15 Javascript
详解 微信小程序开发框架(MINA)
2019/05/17 Javascript
python在命令行下使用google翻译(带语音)
2014/01/16 Python
基于Django contrib Comments 评论模块(详解)
2017/12/08 Python
python with提前退出遇到的坑与解决方案
2018/01/05 Python
python实现比较文件内容异同
2018/06/22 Python
Python错误处理操作示例
2018/07/18 Python
Python线程同步的实现代码
2018/10/03 Python
详解python中的模块及包导入
2019/08/30 Python
The Hut德国站点:时装、家居用品、美容等
2016/09/23 全球购物
英国可持续奢侈品包包品牌:Elvis & Kresse
2018/08/05 全球购物
Hunkemöller瑞士网上商店:欧洲最大的内衣品牌之一
2018/12/03 全球购物
司马光教学反思
2014/02/01 职场文书
信用卡工资证明格式
2014/09/13 职场文书
统计学教授推荐信
2014/09/18 职场文书
2014镇副书记群众路线专题民主生活会思想汇报
2014/09/23 职场文书
班级联欢会主持词
2015/07/03 职场文书
SpringBoot读取Resource下文件的4种方法
2021/07/02 Java/Android
教你使用Ubuntu搭建DNS服务器
2022/09/23 Servers