首发于 JavaScript
Node.js中child_process模块中spawn与exec的异同比较

Node.js中child_process模块中spawn与exec的异同比较

Node.js基于事件驱动来处理并发,它本身是以单线程模式运行的。Node.js通过 child_process 开启子进程执行指定程序。主要包括4个异步进程函数(spawn,exec,execFile,fork)和3个同步进程函数(spawnSync,execFileSync,execSync)。一般我们比较常用的是spawn和exec这两个方法。其中异步进程函数spawn是最基本的创建子进程的函数,其他三个异步函数都是对spawn不同程度的封装。spawn只能运行指定的程序,参数需要在列表中给出,而exec可以直接运行复杂的命令。
默认情况下, stdin stdout stderr 的管道在父 Node.js 进程和衍生的子进程之间建立。这些管道具有有限的(与平台相关)容量。 如果子进程在没有捕获输出的情况下写入超出该限制的 stdout,则子进程将阻塞等待管道缓冲区接受更多的数据。 这与 shell 中的管道行为相同。 如果不需要输出,则使用 { stdio: 'ignore' }
child_process.spawn 方法异步地衍生子进程,并且不阻塞 Node.js 事件循环。而 child_process.spawnSync 方法则以同步的方式提供等效功能,但会阻止事件循环直到衍生的进程退出或终止。
为方便起见, child_process 模块提供了 child_process.spawn() child_process.spawnSync() 的一些同步和异步的替代方法。注意,这些替代方法中的每一个都是基于 child_process.spawn() child_process.spawnSync() 实现的。

  1. child_process.exec() :衍生一个 shell 并在该 shell 中运行命令,当完成时则将 stdout stderr 传给回调函数。
  2. child_process.execFile() :类似于 child_process.exec() ,除了它默认会直接衍生命令且不首先衍生 shell。
  3. child_process.fork() :衍生一个新的 Node.js 进程,并通过建立 IPC 通信通道来调用指定的模块,该通道允许在父进程与子进程之间发送消。
  4. child_process.execSync() child_process.exec() 的同步版本,会阻塞 Node.js 事件循环。
  5. child_process.execFileSync() child_process.execFile() 的同步版本,会阻塞 Node.js 事件循环。

对于某些用例,例如自动化的 shell 脚本, 同步的方法 可能更方便。 但是在大多数情况下,同步的方法会对性能产生重大影响,因为它会停止事件循环直到衍生的进程完成。

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

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
ls.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
ls.on('close', (code) => {
  console.log(`子进程退出码:${code}`);

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

const { exec } = require('child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`执行出错: ${error}`);