node多进程:child_process

72 阅读2分钟

进程的概念

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配基本单位,是操作系统结构的基础。
拿我们在电脑中打开webstorm并且运行一个cli项目来说: image.png OS是指操作系统,那么launchd就是桌面进程,我们在桌面点击启动webstorm就创建了webstorm的进程,此时launchd就是webstorm的父进程,然后在webstorm调用node命令执行一个项目,就又启动了一个执行该项目的进程,在这个项目里面,我们又可以通过child_process API启动很多项目的子进程。

child_process API

exec和execFile

两者的函数签名如下:

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

exec主要用来执行shell命令;而execFile主要用来执行可执行文件,其第二个参数为执行文件执行时注入的参数。其实exec一样可以用来执行可执行文件,不过使用exec时没法注入参数。

spawn

spawn的函数签名如下:

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

入参是命令、参数列表、options,可以看到spawn是没有回调函数的,我们在使用的时候通过它的返回值监听data的方式来处理结果:

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

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

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

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
}); 

值得注意的是,spawn的第一个参数并不能像exec那样用空格隔开当做命令,spawn需要配合第二个参数来使用,比如使用spawn执行npm install时需要这样写:

spawn('npm', ['install'])
// 下面写法是不会执行的
spawn('npm install')

fork

先看fork的函数签名:

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

fork与上述三个方法的不同之处在于使用fork时会再开启一个进程去执行modulePath文件,我们可以使用send去进行两个进程之间的通信:
在父脚本中:

const cp = require('node:child_process');
const n = cp.fork(`${__dirname}/sub.js`);

n.on('message', (m) => {
  console.log('PARENT got message:', m);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
n.send({ hello: 'world' });

然后子脚本 'sub.js' 中:

process.on('message', (m) => {
  console.log('CHILD got message:', m);
});

// Causes the parent to print: PARENT got message: { foo: 'bar', baz: null }
process.send({ foo: 'bar', baz: NaN });

如何选择

  • exec和execFile结果在回调里处理,意味着要等任务执行完成,所以它们适合用在开销比较小的任务。
  • spawn则适合用在比较耗时或者需要不断打印日志的任务,比如执行npm install命令
  • fork适用于耗时操作,它可以开启额外的进程去执行耗时操作,并且能与主进程进行通信。

同步API:execFileSync、execSync、spawnSync

这些API与上述异步API的使用方法和作用都相同,区别是这些API是同步执行,会阻塞代码执行。