浅谈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 相关文章推荐
JavaScript中的关键字"VAR"使用详解 分享
Jul 31 Javascript
分享28款免费实用的 JQuery 图片和内容滑块插件
Dec 15 Javascript
jQuery设置和移除文本框默认值的方法
Mar 09 Javascript
简介JavaScript中Boolean.toSource()方法的使用
Jun 05 Javascript
JavaScript中函数表达式和函数声明及函数声明与函数表达式的不同
Nov 15 Javascript
使用jQuery判断Div是否在可视区域的方法 判断div是否可见
Feb 17 Javascript
有关easyui-layout中的收缩层无法显示标题的解决办法
May 10 Javascript
AngularJS实现表单元素值绑定操作示例
Oct 11 Javascript
基于Vue开发数字输入框组件
Dec 19 Javascript
electron demo项目npm install安装失败的解决方法
Feb 06 Javascript
jQuery仿移动端支付宝键盘的实现代码
Aug 15 jQuery
Vue中强制组件重新渲染的正确方法
Jan 03 Vue.js
除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
玛琪朵 Macchiato
2021/03/03 咖啡文化
如何将一个表单同时提交到两个地方处理
2006/10/09 PHP
PHP 面向对象程序设计(oop)学习笔记 (五) - PHP 命名空间
2014/06/12 PHP
高亮显示web页表格行的javascript代码
2010/11/19 Javascript
jQuery中removeClass()方法用法实例
2015/01/05 Javascript
jquery+html5烂漫爱心表白动画代码分享
2015/08/24 Javascript
js跨浏览器的事件侦听器和事件对象的使用方法
2015/12/17 Javascript
详解Bootstrap创建表单的三种格式(一)
2016/01/04 Javascript
Bootstrap所支持的表单控件实例详解
2016/05/16 Javascript
解决html-jquery/js引用外部图片时遇到看不了或出现403的问题
2017/09/22 jQuery
原生js实现移动端触摸轮播的示例代码
2017/12/22 Javascript
用vue写一个仿简书的轮播图的示例代码
2018/03/13 Javascript
基于vue.js组件实现分页效果
2018/12/29 Javascript
深入浅析Vue中mixin和extend的区别和使用场景
2019/08/01 Javascript
详解webpack打包vue项目之后生成的dist文件该怎么启动运行
2019/09/06 Javascript
vue 使用鼠标滚动加载数据的例子
2019/10/31 Javascript
JS检测浏览器开发者工具是否打开的方法详解
2020/10/02 Javascript
[02:15]2015国际邀请赛选手档案IG.Ferrari 430
2015/07/30 DOTA
centos系统升级python 2.7.3
2014/07/03 Python
解决python3 urllib中urlopen报错的问题
2017/03/25 Python
Python标准模块--ContextManager上下文管理器的具体用法
2017/11/27 Python
python使用socket创建tcp服务器和客户端
2018/04/12 Python
python 求1-100之间的奇数或者偶数之和的实例
2019/06/11 Python
利用Python复制文件的9种方法总结
2019/09/02 Python
python如何求圆的面积
2020/07/01 Python
Python3爬虫里关于Splash负载均衡配置详解
2020/07/10 Python
HTML5仿微信聊天界面、微信朋友圈实例代码
2018/01/29 HTML / CSS
Snapfish英国:在线照片打印和个性化照片礼品
2017/01/13 全球购物
海滩咖啡馆:Beach Cafe
2018/02/02 全球购物
Under Armour安德玛法国官网:美国高端运动科技品牌
2018/06/29 全球购物
英国现代市场:ARKET
2019/04/10 全球购物
大学自主招生自荐信范文
2014/02/26 职场文书
幼儿园教师教育感言
2014/02/28 职场文书
办公室主任岗位承诺书
2014/05/29 职场文书
2014院党委领导班子对照检查材料思想汇报
2014/09/24 职场文书
行政执法作风整顿剖析材料
2014/10/11 职场文书