[TOC]
>[warning] 说明:本文档只说明使用频繁的知识点,有关对应知识的所有具体内容可查看对应的 API 连接
# 1. procss 进程
**`process`对象是一个全局变量,提供有关当前 Node.js 进程的信息并对其进行控制。**
**`process` 全部事件与属性查看官方文档:[http://nodejs.cn/api/process.html#process\_process](http://nodejs.cn/api/process.html#process_process)**
## 1.1 常用的事件
* ### 1.1.1 beforeExit
* node.js 在没有工作调度时会退出(进程结束),此时会优先触发 beforeExit 函数
* 监听 beforeExit 注册的函数可以异步调用,从而继续进程(开始新的工作调度)
* 监听函数将传入 process.exitCode
* 显式终止时不会触发 beforeExit
~~~
// 监听函数
process.on('beforeExit', (code) => {
console.log('进程 beforeExit 事件的代码: ', code);
});
console.log('此消息最新显示');
// 显式终止
process.exit();
此消息最新显示
进程 exit 事件的代码: 0
~~~
* ### 1.1.2 exit
* 进程结束时触发函数
* 监听函数将传入 process.exitCode
* 监听函数内只可同步执行,异步函数无效
~~~
process.on('exit', (code) => {
console.log('进程 exit 事件的代码: ', code);
});
process.on('beforeExit', (code) => {
console.log('进程 beforeExit 事件的代码: ', code);
});
console.log('此消息最新显示');
此消息最新显示
进程 beforeExit 事件的代码: 0
进程 exit 事件的代码: 0
~~~
* ### 1.1.3 message
* 如果使用 IPC 通道衍生 Node.js 进程(在子进程与集群会常用),则只要子进程收到父进程的消息,就会触发事件
* ### 1.1.4 disconnect
* 在 IPC 通道关闭时触发事件,并更改 `process.connected` 为 `false`
* 进程调用`process.disconnect()`的效果和父进程调用[`ChildProcess.disconnect()`](http://nodejs.cn/s/ke6TNp)的一样。
* ### 1.1.5 nextTick
* 将回调函数添加到下一个时间点的队列
~~~
console.log('开始');
process.nextTick(() => {
console.log('下一个时间点的回调');
});
console.log('调度');
开始
调度
下一个时间点的回调
~~~
## 1.2 常用的属性
* ### 1.2.1 env
* process.env 返回包含用户环境的对象
* 进程内可 `增 删 改` 对象属性
~~~
process.env.TEST = 1;
console.log(process.env.TEST);
// 1
delete process.env.TEST;
console.log(process.env.TEST);
// => undefined
~~~
* ### 1.2.2 exitCode
* 进程退出时的退出码
* process.exit(code) 可通过 exit 方法指定退出码
* ### 1.2.3 pid
* 进程标识 PID
* ### 1.2.4 ppid
* 父进程标识 PID
# 2. child_procss 子进程
**`child_procss ` 全部事件与属性查看官方文档:[http://nodejs.cn/api/child\_process.html#child\_process\_child\_process](http://nodejs.cn/api/child_process.html#child_process_child_process)**
## 2.1 创建异步进程
> 创建异步进程的每一个方法都会返回一个 `ChildProcess` 实例
* ### 2.1.1 fork
* 该方法是 `child_process.spawn()` 的一个特例,专门用于衍生新的 Node.js 进程
* 衍生的 Node.js 子进程独立于父进程,但两者之间建立的 IPC 通信通道除外
* 通过 fork 创建的子进程可与父进程互发消息
~~~
const childProcess=require('child_process');
const parent = childProcess.fork('child.js');
parent.send('server', () => {
console.log('父子进程建立连接');
});
// child.js
process.on('message', function (msg) {
if (msg === 'server') {
console.log('子进程收到消息');
}
})
~~~
* ### 2.1.2 spawn
* 该方法使用给定的`command`衍生一个新进程,并带上`args`中的命令行参数
~~~
const childProcess=require('child_process');
const sp = childProcess.spawn('node',['test1.js'],{ cwd:'./test' });
sp.stdout.on('data',function (data) {
console.log('子进程标准输出: '+ data);
sp2.stdin.write(data);
});
sp.on('exit',function(code, signal) {
if (code || code === 0) {
console.log('子进程退出,退出代码为:' + code);
} else {
console.log('子进程退出,退出信号为:' + signal);
}
});
~~~
## 2.2 创建同步进程
> 同步进程将会阻塞 Node.js 事件循环、暂停任何其他代码的执行
* ### 2.2.1 spawnSync
* spawn 同步版,在子进程完全关闭之前该函数不会返回
## 2.3 ChildProcess 类
**ChildProcess 实例代表衍生的子进程**
**实例通过异步创建进程而生成**
*****
**常用事件**
* ### 2.3.1 disconnect
* 断开连接后不能再发法消息,且更改 `subprocess.connected` 属性为`false`,与 `process ` 同名事件使用效果相似
* 调用父进程中的`subprocess.disconnect()`与子进程中的`process.disconnect()`效果一致
* ### 2.3.2 close
* 子进程 stdio 流被关闭时触发
* 与 exit 事件不同,多个进程可能共享同一个 stdio 流
> `options.stdio`选项用于配置在父进程和子进程之间建立的管道
~~~
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.on('close', (code) => {
console.log(`子进程使用代码 ${code} 关闭所有 stdio`);
});
ls.on('exit', (code) => {
console.log(`子进程使用代码 ${code} 退出`);
});
~~~
* ### 2.3.3 exit
* 进程结束后触发
* sp.on('exit', (code, single) => {}) code 与 single 两个值至少一个不为 null
* ### 2.3.5 subprocess.send
*
* ### 2.3.4 message
* 子进程使用 process.send() 发送消息时触发
**常用属性**
* ### 2.3.5 subprocess.channel
* 表示子进程的 IPC 通道
* ### 2.3.6 subprocess.connected
* 表明是否可以从子进程发送和接收消息
* 为 false 时不可发送或接受消息
* ### 2.3.7 subprocess.stdio
* 一个到子进程的管道的稀疏数组,对应于传给[`child_process.spawn()`](http://nodejs.cn/s/CKoDGf)的被设为`'pipe'`值的[`stdio`](http://nodejs.cn/s/ixmPX9)选项中的位置。`subprocess.stdio[0]`、`subprocess.stdio[1]`和`subprocess.stdio[2]`也分别可用作`subprocess.stdin`、`subprocess.stdout`和`subprocess.stderr`。
* ### 2.3.8 subprocess.stdout
* 子进程的`stdout`的可读流。
* `subprocess.stdout` = `subprocess.stdio[1]` ; `stdio[1]`被设置为`'pipe'`以外的任何值,则该值将会是`null`
# 3. cluster 集群
**该模块可以创建共享服务器端口的子进程。**
**单个 Node.js 实例运行在单个线程中,通过启用一组 Node.js 进程,来充分利用多核系统**
**有关集群的全部内容可查看官方文档:[http://nodejs.cn/api/cluster.html#cluster\_cluster](http://nodejs.cn/api/cluster.html#cluster_cluster)**
~~~
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 衍生工作进程。
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 工作进程可以共享任何 TCP 连接。
// 在本例子中,共享的是 HTTP 服务器。
http.createServer((req, res) => {
res.writeHead(200);
res.end('你好世界\n');
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
主进程 2796 正在运行
工作进程 14360 已启动
工作进程 12140 已启动
工作进程 6276 已启动
工作进程 14372 已启动
~~~
## 3.1 work 类
> 工作进程由`child_process.fork()`方法创建,因此它们可以使用 IPC 和父进程通信,从而使各进程交替处理连接服务。
**常用事件**
* ### 3.1.1 disconnect
* 特定于此工作进程
~~~
cluster.fork().on('disconnect', () => {
// 工作进程已断开连接。
});
~~~
**常用属性**
* ### 3.1.2 worker.id
* 工作进程的标识
* ### 3.1.3 worker.process
* 为 child_process.fork() 返回的对象
* 在工作进程中为全局对象
## 3.2 常用事件
* ### 3.2.1 fork
* 新的工作进程被衍生时触发
* 可用来记录工作进程活动
> 可以直接调用衍生新的工作进程
~~~
const timeouts = [];
function errorMsg() {
console.error('连接出错');
}
cluster.on('fork', (worker) => {
timeouts[worker.id] = setTimeout(errorMsg, 2000);
});
cluster.on('listening', (worker, address) => {
clearTimeout(timeouts[worker.id]);
});
cluster.on('exit', (worker, code, signal) => {
clearTimeout(timeouts[worker.id]);
errorMsg();
});
~~~
* ### 3.2.2 exit
* 任何工作进程关闭时触发
* 可用于重启工作进程
~~~
cluster.on('exit', (worker, code, signal) => {
console.log('工作进程 %d 关闭 (%s). 重启中...',
worker.process.pid, signal || code);
cluster.fork();
});
~~~
* ### 3.2.3 online
* 衍生工作进后,工作进程运行时触发
* 主进程衍生工作进程时触发`'fork'` 而不是 online
~~~
cluster.on('online', (worker) => {
console.log('工作进程被衍生后响应');
});
~~~
## 3.3 常用属性
* ### 3.3.1 cluster.isMaster
* 该进程为主进程时为 true
* ### 3.3.2 cluster.isWorker
* 不为主进程时为 true
* ### 3.3.3 cluster.worker
* 当前工作进程对象
~~~
const cluster = require('cluster');
if (cluster.isMaster) {
console.log('这是主进程');
cluster.fork();
cluster.fork();
} else if (cluster.isWorker) {
console.log(`这是工作进程 #${cluster.worker.id}`);
}
~~~
* ### 3.3.4 cluster.workers
* 存储所有活跃工作进程对象
* 工作进程断开连接以及推出后从workers中移除
~~~
// 遍历所有工作进程。
function eachWorker(callback) {
for (const id in cluster.workers) {
callback(cluster.workers[id]);
}
}
eachWorker((worker) => {
worker.send('通知所有工作进程');
});
~~~