nodeJS
来源:互联网 发布:淘宝店铺装修设置单价 编辑:程序博客网 时间:2024/06/11 15:47
Process 进程 、child_process 子进程 、Cluster 集群
虽然 Node.js 把许多东西从操作系统中抽象出来,但你依然在操作系统中运行,而且可能想要更直接的与他交互,Node 中可以使用系统中已经存在的进程,或者创建新的子进程来做各种工作,虽然 Node 本身是一个 ‘胖’ 线程,带有单独一个事件循环,但你可以任意的开启其他进程( 线程)在事件循环外工作 – 《Node 即学即用》
参考
- 深入浅出 Node.js
- Node.js 文档
- JavaScript 标准参考教程 Node.js
1. Process 进程
说明
process 对象是 Node 的一个全局对象,提供当前 Node 进程的信息,他可以在脚本的任意位置使用,不必通过 require 命令加载。
属性 API
process.argv
属性,返回一个数组,包含了启动 node 进程时的命令行参数process.env
返回包含用户环境信息的对象,可以在 脚本中对这个对象进行增删改查的操作process.pid
返回当前进程的进程号process.platform
返回当前的操作系统process.version
返回当前 node 版本process.execPath
返回启动 Node.js 进程的可执行文件所在的绝对路径process.execArgv
返回 在 Node 可执行文件与脚本文件之间的命令行参数process.stdin
标准输入,实现Duplex
流(可读、可写)process.stdout
标准输出,实现Duplex
流(可读、可写),write()
方法相当于console.log()
process.stderr
标准错误
// # node index.js name test console.log(process.argv); /* [ '/usr/local/bin/node', // process.execPath 启动 Node 进程的可执行文件所在的绝对路径 '/Users/xxx/node-test/index.js', // 当前执行的 javascript 文件路径 'name', // 其他命令行参数 'test' ] */ process.env.test = 'test'; // 增加 console.log(process.env.test); // test 查询 process.env.test = 'new'; // 改 console.log(process.env.test); // new delete process.env.test; // 删除 console.log(process.env.test); // undefined /* 新建环境变量 NODE_ENV,标注开发阶段还是生产阶段 命令行可以使用 export NODE_ENV=production & node index.js */ process.env.NODE_ENV = 'production' console.log(process.pid); // 3105 console.log(process.platform); // darwin console.log(process.version); // v8.9.0 console.log(process.execPath); // /usr/local/bin/node // # node --harmony index.js console.log(process.execArgv); // [ '--harmony' ] let count = 0; process.stdin.on('data', function (chunk) { process.stdout.write(count++ + ' = ' + chunk); }) process.stdin.on('end', function () { process.stdout.write('end'); })
方法 API
process.cwd()
返回 node.js 进程当前工作目录process.chdir()
变更 node.js 进程的工作目录process.nextTick(fn)
将任务放到当前事件循环的尾部,添加到 ‘next tick’ 队列,一旦当前事件轮询队列的任务全部完成,在 next tick 队列中的所有 callback 会被依次调用process.exit()
退出当前进程,很多时候是不需要的process.kill(pid[,signal])
给指定进程发送信号,包括但不限于结束进程process.emitWarning()
发出特定或者定制的进程警告 可以通过process.on('warning)
监听这些警告
console.log(process.cwd()); // /Users/temp/node-test process.chdir('../'); console.log(process.cwd()); // / Users/temp let count = 0; process.on('warning', function (warning) { console.log(warning); }) process.stdin.on('data', function (chunk) { process.nextTick(function () { console.log('next tick'); }) process.stdout.write(count++ + '=' + chunk); if (count > 3) { process.emitWarning('something warning', { code: 'WARNING_SOME', detail: 'this is warning something' }) process.exit(); // 退出进程 process.kill(process.pid); // 杀死进程 } /* ss undefined undefined */ })
process 事件
beforeExit
事件,在 Node 清空了 EventLoop 之后,再没有任何待处理任务时触发,可以在这里再部署一些任务,使得 Node 进程不退出,显示的终止程序时(process.exit()),不会触发exit
事件,当前进程退出时触发,回调函数中只允许同步操作,因为执行完回调后,进程金辉退出uncaughtException
事件,当前进程抛出一个没有捕获的错误时触发,可以用它在进程结束前进行一些已分配资源的同步清理操作,尝试用它来恢复应用的正常运行的操作是不安全的warning
事件,任何 Node.js 发出的进程警告,都会触发此事件Signal Events
信号事件,当 Node.js 进程接收到一个信号时触发
let count = 0; process.on('beforeExit', function () { console.log('beforeExit'); }) process.on('exit', function (code) { console.log('exit', code); }) process.on('uncaughtException', function (err) { console.log('uncaughtException', err); }) process.on('warning', function (warning) { console.log('warning', warning); }) process.on('SIGHUP', function () { console.log('SIGHUP'); }) process.stdout.write('xxx'); process.kill(process.pid, 'SIGHUP') /* xxx SIGHUP beforeExit exit 0 */
2. child_process 子进程
说明
child_process 模块用于新建子进程,子进程的运行结果存储在系统缓存中(最大200k),等到子进程运行结束后,主进程再调用回调函数读取子进程的运行结果
通过 fork() 等 API,创建子进程后,为了实现父子进程之间的通信,父子进程之间将会创建 IPC 通道,通过 IPC 通道父子进程之间才能通过 message 和 send() 传递消息
默认情况下,在 Node.js 的父进程与衍生进程之间会建立 stdin、stdout、stderr 的管道,数据能以非阻塞的方式在管道中流通
创建子进程
1. child_process.spawn() child_process.spwanSync()
spawn()
会异步的衍生子进程,spawnSync()
方法则以同步的方式提供同样的功能 ,但会阻塞事件循环、知道衍生的子进程退出或者终止参数
- 1)command: 所要执行的 shell 脚本命令
- 2)args: 字符串参数列表
- 3)options: 配置额外的选项:cwd: 子进程的当前工作目录;env:环境变量键值对…
// test.js 内容 process.stdout.write('this is child back'); // index.js 内容 执行 node index.js const child_process = require('child_process'); const child = child_process.spawn('node', ['test.js'], { cwd: './' }); child.stdout.setEncoding('utf-8'); child.stdout.on('data', function (data) { console.log('listen in process', data); // listen in process this is child back }) const childSync = child_process.spawnSync('node', ['test.js'], { cwd: './' }) console.log(childSync); // pid stdout error ...
一下的接口都是为了方便起见,在 这两个接口(
spawn()、spawnSync()
)之上实现的
2. child_process.exec() child_process.execSync()
衍生出一个 shell,然后在 shell 中执行命令,且缓冲任何产生的输出,运行结束后调用回调函数
- 1)command: 要运行的命令,空格分割
- 2)options: 选填,cwd: 子进程的工作目录;env: 环境变量键值对
- 3)callback: 回调,会传入三个参数,error: 错误信息;stdout:标准输出显示结果;stdrr: 标准错误显示结果
const child_process = require('child_process'); child_process.exec('node test.js', function (error, stdout, stderr) { if (error) { return console.log(error); } console.log('stdout', stdout); console.log('stderr', stderr); }) const child = child_process.exec('node test.js'); child.stdout.on('data', function (data) { console.log('listen ', data.toString()); }) const childSync = child_process.execSync('node test.js'); console.log(childSync.toString());
3. child_process.execFile() child_process.execFileSync()
类似 child_process.exec() 函数,除了不衍生一个 shell ,而是指定的可执行的 file 被直接衍生为一个新的进程,更加高效
- 1)file: 要运行的可执行文件的名称或者路径
- 2)args: 可选,字符串参数列表
- 3)options: 配置项 与 child_process.exec() 一致
- 4)callback: 回调 error 错误;stdout 标准输出;stderr 标准错误
const child_process = require('child_process'); child_process.execFile('node', ['test.js'], function (error, stdout, stderr) { if (error) { return console.log(error); } console.log('stdout', stdout); console.log('stderr', stderr); }) const childSync = child_process.execFileSync('node', ['test.js']); console.log(childSync.toString());
4. child_process.fork() send()
fork() 用于直接创建一个子进程会返回一个 childProcess 对象,与spawn方法不同的是,fork 会在父进程与子进程间,建立一个通信管道,用于进程之间的通信
- 1)modulePath: 要在子进程中运行的模块
- 2)args: 字符串参数列表
- 3)option: 配置项 cwd: 子进程当前工作目录;env: 环境白变量;execpath: 用来创建子进程的执行路径
send() 用于向新进程发送消息,新进程中通过监听
message
事件,来获取消息
const child_process = require('child_process'); const child = child_process.fork('./test.js'); // 监听 message 事件,获取子进程返回数据 child.on('message', function (m) { console.log('process get', m); }) child.send({parentID: process.pid});
5. 创建方法的比较
- spawn():启动一个子进程来执行命令
- exec():启动一个子进程来执行命令,并且通过回调函数通知子进程状况
- execFile():启动一个子进程来执行可执行文件
- fork():是 spawn() 的一个特例,创建子进程只需要指定要执行的 javascript 文件模块即可,子进程返回一个 child_process 对象,并附加父子进程间的通信渠道
- exec() 与 execFile() 创建时可以指定 timeout 属性设置超时时间,一旦创建的进程运行超过设定的时间将会被杀死
子进程对象的事件与属性
事件
close
事件,当子进程的 ‘stdio’ 流被关闭时触发disconnect
事件,在父进程中 subprocess.disconnect() 或者在子进程中调用 process.disconnect() 都会触发,断开后将关闭 IPC 通道,不能再发送或者接受消息error
事件,当子进程无法被复制创建、无法被杀死、无法发送消息时会触发exit
事件, 子进程结束后会触发,回调参数 code:退出码;signal: 被终止时的信号message
事件,父、子进程间通信,接受信息用
属性
connected
属性,表明是否仍可以从一个子进程发送和接收消息disconnect()
方法,关闭父进程与子进程之间的 IPC 通道,一旦没有其他的连接使其保持活跃,则允许子进程正常退出。kill([signal])
方法, 向子进程发送一个信号,不写参数默认结束子进程killed
属性,表明该子进程已经成功地被 subprocess.kill() 终止pid
属性,子进程的进程标识send
方法,父进程和子进程之间建立了一个 IPC 通道时,用于发送信息
// 子进程 test.js process.on('message', function (m) { console.log('child process get ', m); if (m === 0) process.send(3); }) // 主进程 const child_process = require('child_process'); const child = child_process.fork('./test.js'); child.on('close', function (code, signal) { console.log('close code', code); console.log('close signal', signal); }) child.on('exit', function (code, signal) { console.log('exit code', code); console.log('exit signal', signal); }) child.on('disconnect', function () { console.log('disconnect', child.connected); }) child.on('error', function (err) { console.log('error', err); }) // 监听 message 事件,获取子进程返回数据 child.on('message', function (m) { console.log('process get', m); if (m === 1) child.disconnect(); if (m === 3) child.kill(); console.log(child.killed); }) child.send(0);
3. Cluster 集群
说明
Node.js 默认单进程运行,对于多核 CPU 的计算机来说,这样做效率很低,因为只有一个核在运行,其他核都在闲置,面对单进程单线程对多核使用不足的问题,前人的经验是启动多进程。理想的状态下每个进程各自利用一个 CPU ,以此实现多核 CPU 的利用
Master-Worker模式:Cluster 模块允许设立一个主进程和若干个 worker 进程,由主进程监控和协调 worker 进程的运行,worker 之间采用进程间通信交换信息,cluster 模块内置一个负载均衡器,协调各个进程之间的负载。这是典型的分布式架构中用于并行处理业务的模式,具备较好的可伸缩性和稳定性。主进程不负责具体的业务处理,而是负责调度或管理工作进程,他是趋向于稳定为。工作进程负责具体的业务处理。
通过 fork() 复制的进程都是一个独立的进程,这个进程中有着独立的 V8 实例。 fork() 进程是昂贵的。Node 通过事件驱动的方式在单线程上解决了大并发的问题,启动多个进程只是为了充分将 CPU 资源利用起来,而不是为了解决并发问题
cluster 模块的属性和方法
isMaster
属性,返回该进程是不是主进程isWorker
属性,返回该进程是不是工作进程fork()
方法,只能通过主进程调用,衍生出一个新的 worker 进程,返回一个 worker 对象disconnect([callback])
方法,当所有的工作进程都断开链接后,运行主进程优雅的关闭setupMaster([settings])
方法,用于修改 fork() 默认行为,一旦调用,将会按照cluster.settings进行设置。settings
属性,用于配置,参数 exec: worker文件路径;args: 传递给 worker 的参数;execArgv: 传递给 Node.js 可执行文件的参数列表workers
属性,表示当前活跃进程的 hash 表 key 为 worker 进程 id
cluster 模块的事件
fork
事件,当新的工作进程被 fork 时触发,可以用来记录工作进程活动listening
事件,当一个工作进程调用listen()
后触发,事件处理器两个参数 worker:工作进程对象;address: 包括 address、port、addressTypeonline
事件,复制好一个工作进程后,工作进程主动发送一条 online 消息给主进程,主进程收到消息后触发,回调参数 worker 对象disconnect
事件,主进程和工作进程之间 IPC 通道断开后触发exit
事件,有工作进程退出时触发,回调参数 worker 对象、code 退出码、signal 进程被 kill 时的信号setup
事件,cluster.setupMaster()
执行后触发message
事件,当主进程接收到任意工作进程发送的消息后触发,参数 worker 对象、message 消息,handle 处理,旧版本没有 worker 参数
worker 对象的属性与方法
在一个主进程中使用
cluster.workers
来获取 worker 对象;在一个工作进程中,使用cluster.worker
来获取 worker 对象
id
属性,返回当前 worker 的 进程编号process
属性,返回 worker 所在的进程对象send()
方法,发送一个消息给工作进程或者主进程,参数 message 、callbackdisconnect()
方法,在一个工作进程中,调用此方法会关闭所有 server,并等待这些 server 的close
事件执行,然后关闭 IPC 管道isConnected()
方法,返回是否链接到主进程isDead()
方法,返回工作进程是否被终止kill([signal])
方法,kill 工作进程
// 主进程文件 index.js const os = require('os'); const cluster = require('cluster'); // isMaster 是不是主进程 console.log(cluster.isMaster); // true // 是不是 worker 工作进程 console.log(cluster.isWorker); // false // setupMaster 修改 fork 默认行为 cluster.setupMaster({ exec: 'worker.js' // worker 进程之行文件的路径 }) if (cluster.isMaster) { for (let i = 0; i < os.cpus().length; i++) { // fork 衍生 worker 子进程 cluster.fork(); } // workers 活跃的进程 console.log(cluster.workers); cluster.on('fork', function (worker) { console.log('fork = ' + worker.id) }) cluster.on('listening', function (worker, address) { console.log('worker ' + worker.id + ' listen ' + address.address + ':' + address.port); }) cluster.on('online', function (worker) { console.log('worker ' + worker.id + ' online'); }) cluster.on('disconnect', function (worker) { console.log('disconnected worker ' + worker.id); }) cluster.on('exit', function (worker, code, signal) { console.log('exit ' + worker.id + ' code = ' + code + ' signal ' + signal); }) cluster.on('setup', function () { console.log('have setup'); }) cluster.on('message', function (worker, message, handle) { console.log('got message from ' + worker.id + ' message ' + message); worker.id === 2 && setTimeout(function () { worker.send('disconnect'); }, 1000) worker.id === 3 && setTimeout(function () { worker.send('kill'); }, 1000) }) }
worker 对象的事件
listening
和cluster.on(‘listening’)事件类似,但针对特定的工作进程online
和cluster.on(‘online’)事件类似,但针对特定的工作进程disconnect
事件,主进程和工作进程之间 IPC 通道断开后触发exit
事件,当前工作进程退出时触发,回调参数 code 退出码、signal 进程被 kill 时的信号message
事件,当前进程接收主进程发送的消息后触发,message 消息,handle 处理,旧版本没有 worker 参数error
事件,此事件和child_process.fork()
提供的error事件相同
// 工作进程文件 worker.js const cluster = require('cluster'); const http = require('http'); // cluster.worker 当前子进程 const worker = cluster.worker; // id 进程编号 console.log('in worker id', worker.id); // process worker 所在的进程对象 // console.log('in worker process', worker.process); // isConnected 是否链接到主进程 console.log('worker ' + worker.id + ' connected ' + worker.isConnected()); // send 发送消息 worker.send('first message', function () { console.log('first message callback'); }) worker.on('disconnect', function () { console.log('worker ' + worker.id + ' disconnect in'); }) worker.on('error', function (err) { console.log('worker ' + worker.id + ' error', err); }) worker.on('exit', function (code, signal) { console.log('worker ' + worker.id + ' exit '); }) worker.on('listening', function (address) { console.log('worker ' + worker.id + ' listerner', address); }) worker.on('message', function (msg) { if (msg === 'disconnect') { // disconnect 断开链接 worker.disconnect(); // console.log('worker is dead ' + worker.isDead()); } if (msg === 'kill') { // kill 结束进程 worker.kill(); } }) http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000, '10.15.32.49');
- nodejs
- NodeJs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- NodeJs
- nodejs
- NodeJS
- nodejs
- nodejs
- nodejs
- NodeJS
- nodejs
- 优达(Udacity)-机器学习基础-交叉验证
- eclipse屏蔽xml文件报错
- 如何创建ramdisk
- f5禁止
- 匿名内部类 通过接口来实现
- nodeJS
- 条款16:成对使用new和delete的时候要采取相同形式
- linux文件操作
- 董宁:将区块链技术用于民生,才能发挥更大价值
- vue项目开发实战(三)——vue-router
- 图像卷积与滤波的一些知识点
- Leetcode 题解
- opencv_tutorial_code学习——图片叠加
- php使用curl发送post请求