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

前端之家收集整理的这篇文章主要介绍了浅谈Node.js 子进程与应用场景前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

背景

由于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

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

基础使用

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});
});

常用参数

dio: Array | String,detached: Boolean,shell: Boolean,uid: Number,gid: Number }

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

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

exec

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

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 child = spawn('find . -type f | wc -l',{
stdio: 'inherit',shell: true
});

child.stdout.on('data',signal: ${signal}`);
});

execFile

执行一个文件

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

fork

执行一个 Node.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' });

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 中部分功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

猜你在找的Node.js相关文章