浅谈Node.js 子进程与应用场景


Posted in Javascript onJanuary 24, 2018

背景

由于ons(阿里云 RocketMQ 包)基于 C艹 封装而来,不支持单一进程内实例化多个生产者与消费者,为了解决这一问题,使用了 Node.js 子进程。

在使用的过程中碰到的坑

发布:进程管理关闭主进程后,子进程变为操作系统进程(pid 为 1)

几种解决方案

将子进程看做独立运行的进程,记录 pid,发布时进程管理关闭主进程同时关闭子进程

主进程监听关闭事件,主动关闭从属于自己的子进程

子进程种类

  1. spawn:执行命令
  2. exec:执行命令(新建 shell)
  3. execFile:执行文件
  4. fork:执行文件

子进程常用事件

  1. exit
  2. close
  3. error
  4. message

close 与 exit 是有区别的,close 是在数据流关闭时触发的事件,exit 是在子进程退出时触发的事件。因为多个子进程可以共享同一个数据流,所以当某个子进程 exit 时不一定会触发 close 事件,因为这个时候还存在其他子进程在使用数据流。

子进程数据流

  1. stdin
  2. stdout
  3. stderr

因为是以主进程为出发点,所以子进程的数据流与常规理解的数据流方向相反,stdin:写入流,stdout、stderr:读取流。

spawn

spawn(command[, args][, options])

执行一条命令,通过 data 数据流返回各种执行结果。

基础使用

const { spawn } = require('child_process');

const child = spawn('find', [ '.', '-type', 'f' ]);
child.stdout.on('data', (data) => {
  console.log(`child stdout:\n${data}`);
});

child.stderr.on('data', (data) => {
  console.error(`child stderr:\n${data}`);
});

child.on('exit', (code, signal) => {
  console.log(`child process exit with: code $[code], signal: ${signal}`);
});

常用参数

{
  cwd: String,
  env: Object,
  stdio: Array | String,
  detached: Boolean,
  shell: Boolean,
  uid: Number,
  gid: Number
}

重点说明下 detached 属性,detached 设置为 true 是为子进程独立运行做准备。子进程的具体行为与操作系统相关,不同系统表现不同,Windows 系统子进程会拥有自己的控制台窗口,POSIX 系统子进程会成为新进程组与会话负责人。

这个时候子进程还没有完全独立,子进程的运行结果会展示在主进程设置的数据流上,并且主进程退出会影响子进程运行。当 stdio 设置为 ignore 并调用 child.unref(); 子进程开始真正独立运行,主进程可独立退出。

exec

exec(command[, options][, callback])

执行一条命令,通过回调参数返回结果,指令未执行完时会缓存部分结果到系统内存。

const { exec } = require('child_process');

exec('find . -type f | wc -l', (err, stdout, stderr) => {
  if (err) {
    console.error(`exec error: ${err}`);
    return;
  }

  console.log(`Number of files ${stdout}`);
});

两全其美 —— spawn 代替 exec

由于 exec 的结果是一次性返回,在返回前是缓存在内存中的,所以在执行的 shell 命令输出过大时,使用 exec 执行命令的方式就无法按期望完成我们的工作,这个时候可以使用 spawn 代替 exec 执行 shell 命令。

const { spawn } = require('child_process');

const child = spawn('find . -type f | wc -l', {
  stdio: 'inherit',
  shell: true
});

child.stdout.on('data', (data) => {
  console.log(`child stdout:\n${data}`);
});

child.stderr.on('data', (data) => {
  console.error(`child stderr:\n${data}`);
});

child.on('exit', (code, signal) => {
  console.log(`child process exit with: code $[code], signal: ${signal}`);
});

execFile

child_process.execFile(file[, args][, options][, callback])

执行一个文件

与 exec 功能基本相同,不同之处在于执行给定路径的一个脚本文件,并且是直接创建一个新的进程,而不是创建一个 shell 环境再去运行脚本,相对更轻量级更高效。但是在 Windows 系统中如 .cmd 、 .bat 等文件无法直接运行,这是 execFile 就无法工作,可以使用 spawn、exec 代替。

fork

child_process.fork(modulePath[, args][, options])

执行一个 Node.js 文件

// parent.js

const { fork } = require('child_process');

const child = fork('child.js');

child.on('message', (msg) => {
  console.log('Message from child', msg);
});

child.send({ hello: 'world' });
// child.js

process.on('message', (msg) => {
  console.log('Message from parent:', msg);
});

let counter = 0;

setInterval(() => {
  process.send({ counter: counter++ });
}, 3000);

fork 实际是 spawn 的一种特殊形式,固定 spawn Node.js 进程,并且在主子进程间建立了通信通道,让主子进程可以使用 process 模块基于事件进行通信。

子进程使用场景

  1. 计算密集型系统
  2. 前端构建工具利用多核 CPU 并行计算,提升构建效率
  3. 进程管理工具,如:PM2 中部分功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
经验几则 推荐
Sep 05 Javascript
关于js拖拽上传 [一个拖拽上传修改头像的流程]
Jul 13 Javascript
jquery插件实现鼠标经过图片右侧显示大图的效果(类似淘宝)
Feb 04 Javascript
js中top/parent/frame概述及案例应用
Feb 06 Javascript
javascript中强制执行toString()具体实现
Apr 27 Javascript
微信小程序-获得用户输入内容
Feb 13 Javascript
jQuery简单实现向列表动态添加新元素的方法示例
Dec 25 jQuery
AngularJS实现的锚点楼层跳转功能示例
Jan 02 Javascript
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
May 27 Javascript
layui 弹出层回调获取弹出层数据的例子
Sep 02 Javascript
vue实现pdf文档在线预览功能
Nov 26 Javascript
Vue过渡效果之CSS过渡详解(结合transition,animation,animate.css)
Feb 05 Javascript
除Console.log()外更多的Javascript调试命令
Jan 24 #Javascript
深入理解node.js http模块
Jan 24 #Javascript
微信、QQ、微博、Safari中使用js唤起App
Jan 24 #Javascript
基于node打包可执行文件工具_Pkg使用心得分享
Jan 24 #Javascript
Angular整合zTree的示例代码
Jan 24 #Javascript
使用classList来实现两个按钮样式的切换方法
Jan 24 #Javascript
基于vue.js 2.x的虚拟滚动条的示例代码
Jan 23 #Javascript
You might like
PHP-redis中文文档介绍
2013/02/07 PHP
ThinkPHP3.1新特性之Action参数绑定
2014/06/19 PHP
ThinkPHP实例化模型的四种方法概述
2014/08/22 PHP
php中最简单的字符串匹配算法
2014/12/16 PHP
PHP获取当前日期和时间及格式化方法参数
2015/05/11 PHP
[原创]php逐行读取txt文件写入数组的方法
2015/07/02 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
ThinkPHP5框架缓存查询操作分析
2018/05/30 PHP
php设计模式之观察者模式定义与用法经典示例
2019/09/19 PHP
js调用flash的效果代码
2008/04/26 Javascript
JavaScript Perfection kill 测试及答案
2010/03/23 Javascript
深入理解javascript的执行顺序
2014/04/04 Javascript
使用coffeescript编写node.js项目的方法汇总
2015/08/05 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
微信小程序云开发修改云数据库中的数据方法
2019/05/18 Javascript
Antd中单个DatePicker限定时间输入范围操作
2020/10/29 Javascript
vue+echarts实现中国地图流动效果(步骤详解)
2021/01/27 Vue.js
[09:40]DAC2018 4.5 SOLO赛 MidOne vs Miracle
2018/04/06 DOTA
[51:06]DOTA2-DPC中国联赛 正赛 Elephant vs Aster BO3 第二场 1月26日
2021/03/11 DOTA
使用python Django做网页
2013/11/04 Python
Python实现自动为照片添加日期并分类的方法
2017/09/30 Python
浅谈Python peewee 使用经验
2017/10/20 Python
使用python实现ANN
2017/12/20 Python
利用pyinstaller将py文件打包为exe的方法
2018/05/14 Python
Python实现的简单线性回归算法实例分析
2018/12/26 Python
python3.7 使用pymssql往sqlserver插入数据的方法
2019/07/08 Python
Pytorch实现神经网络的分类方式
2020/01/08 Python
django自定义非主键自增字段类型详解(auto increment field)
2020/03/30 Python
django 获取字段最大值,最新的记录操作
2020/08/09 Python
Python实现像awk一样分割字符串
2020/09/15 Python
海淘母婴商城:国际妈咪
2016/07/23 全球购物
应届生文秘专业个人自荐信格式
2013/09/21 职场文书
募捐倡议书
2014/04/14 职场文书
2014年财务人员工作总结
2014/11/11 职场文书
企业介绍信范文
2015/01/30 职场文书
AndroidStudio图片压缩工具ImgCompressPlugin使用实例
2022/08/05 Java/Android