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

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)。
特殊的情况,消息中 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

时间: 2016-10-27

Nodejs极简入门教程(三):进程_node.js的相关文章

Nodejs极简入门教程(二):定时器_node.js

setTimeout 和 clearTimeout 复制代码 代码如下: var obj = setTimeout(cb, ms); setTimeout 用于设置一个回调函数 cb,其在最少 ms 毫秒后被执行(并非在 ms 毫秒后马上执行).setTimeout 返回值可以作为 clearTimeout 的参数,clearTimeout 用于停止定时器,这样回调函数就不会被执行了. setInterval 和 clearInterval 复制代码 代码如下: var obj = setInt

Nodejs极简入门教程(一):模块机制_node.js

JavaScript 规范(ECMAScript)没有定义一套完善的能适用于大多数程序的标准库.CommonJS 提供了一套 JavaScript 标准库规范.Node 实现了 CommonJS 规范. 模块基础 在 Node 中,模块和文件是一一对应的.我们定义一个模块: 复制代码 代码如下: // circle.js var PI = Math.PI;   // 导出函数 area exports.area = function(r) {     return PI * r * r; }  

Node.js+Express配置入门教程详解_node.js

Node.js是一个Javascript运行环境(runtime).实际上它是对Google V8引擎进行了封装.V8引 擎执行Javascript的速度非常快,性能非常好.Node.js对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好.Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快.易于扩展的网络应用.Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行的数据密集型

Golang极简入门教程(三):并发支持_Golang

Golang 运行时(runtime)管理了一种轻量级线程,被叫做 goroutine.创建数十万级的 goroutine 是没有问题的.范例: 复制代码 代码如下: package main   import (     "fmt"     "time" )   func say(s string) {     for i := 0; i < 5; i++ {         time.Sleep(100 * time.Millisecond)       

JavaScript极简入门教程(三):数组_javascript技巧

阅读本文需要有其他语言的编程经验. 在 JavaScript 中数组是对象(而非线性分配的内存). 通过数组 literal 来创建数组: 复制代码 代码如下: var empty = []; var numbers = [     'zero', 'one', 'two', 'three', 'four',     'five', 'six', 'seven', 'eight', 'nine' ]; empty[1] // undefined numbers[1] // 'one' empty

Golang极简入门教程(一):基本概念_Golang

安装 Golang 在 http://golang.org/dl/ 可以下载到 Golang.安装文档:http://golang.org/doc/install. Hello Go 我们先创建一个文件 hello.go: 复制代码 代码如下: package main   import "fmt"   func main() {     fmt.Printf("hello Golang\n"); } 执行此程序: 复制代码 代码如下: go run hello.g

JavaScript极简入门教程(一):基础篇_javascript技巧

阅读本文需要有其他语言的编程经验. 开始学习之前 大多数的编程语言都存在好的部分和差的部分.本文只讲述 JavaScript 中好的部分,这是因为: 1.仅仅学习好的部分能够缩短学习时间 2.编写的代码更加健壮 3.编写的代码更加易读 4.编写的代码更加易于维护 弱类型和强类型 通常来说,越早的修复错误,为之付出的代价就越小.强类型语言的编译器可以在编译时检查某些错误.而 JavaScript 是一门弱类型语言,其解释器无法检查类型错误,但实践表明: 1.强类型能够避免的错误并不是那些关键性错误

Golang极简入门教程(四):编写第一个项目_Golang

workspace Golang 的代码必须放置在一个 workspace 中.一个 workspace 是一个目录,此目录中包含几个子目录: 1.src 目录.包含源文件,源文件被组织为包(一个目录一个包) 2.pkg 目录.包含包对象(package objects) 3.bin 目录.包含可执行的命令 包源文件(package source)被编译为包对象(package object),命令源文件(command source)被编译为可执行命令(command executable).

Golang极简入门教程(二):方法和接口_Golang

方法 在 Golang 中没有类,不过我们可以为结构体定义方法.我们看一个例子: 复制代码 代码如下: package main   import (     "fmt"     "math" )   type Vertex struct {     X, Y float64 }   // 结构体 Vertex 的方法 // 这里的方法接收者(method receiver)v 的类型为 *Vertex func (v *Vertex) Abs() float64