Node.js Spawn与Execute的区别

115

我正在观看一段在线的Node.js培训视频,视频中的讲解者提到:"对于需要处理大量数据的长时间运行的进程,使用spawn更好,而对于短小精悍的数据,则使用execute更合适。"

这是为什么呢?child_process模块中的spawn和execute函数有什么区别?在何时应该选择它们中的哪一个?

4个回答

132
主要区别在于,spawn 更适合于具有大量输出的长时间运行进程。这是因为 spawn 使用子进程流式输入/输出。另一方面,exec 在一个小型缓冲区(默认情况下为1MB,在 v11.x 版本之前为 200 KB)中缓存输出。 exec 首先生成一个子 shell,然后尝试执行您的进程。简而言之,如果您需要从子进程流式传输大量数据,请使用 spawn;如果您需要 shell 管道、重定向甚至同时运行多个程序等功能,请使用 exec
一些有用的链接 - DZone Hacksparrow

我也是Node的初学者。我注意到execspawn都返回ChildProcess对象。文档说spawn流式传输stdout,而exec则将其缓冲,所以我尝试了这个:cp.stdout.on("data", ...),其中cp是由exec返回的。结果发现数据也是一块一块地流出来的。我有点困惑。 - Zhou
4
你可以使用 exec 返回的 ChildProcess 对象,类似于使用 spawn,但这有点违背了使用 exec 的初衷,因为该函数抽象了处理流的需要。然而,在幕后这些流仍然存在,exec 只是帮你收集了它们的数据。你发现的只是在使用 exec 时那些流仍然对你可用。然而,通常没有真正需要使用它们。 - Thomas Watson

81
  • spawn()创建的子进程:

    • 不会生成一个shell
    • 通过流(stream)传输子进程返回的数据(数据流是连续的)
    • 没有数据传输大小限制
  • exec()创建的子进程:

    • 会在生成的shell中执行指定命令
    • 会缓存数据(等待进程关闭并一次性传输所有数据)
    • 在Node.js v12.x之前,最大数据传输量为200KB(默认情况下),但自Node.js v12.x起已增加到1MB(默认情况下)

-main.js(文件)

var {spawn, exec} = require('child_process');

    // 'node' is an executable command (can be executed without a shell) 
    // uses streams to transfer data (spawn.stout)  
var spawn = spawn('node', ['module.js']);     
spawn.stdout.on('data', function(msg){         
    console.log(msg.toString())
});

    // the 'node module.js' runs in the spawned shell 
    // transfered data is handled in the callback function 
var exec = exec('node module.js', function(err, stdout, stderr){
    console.log(stdout);
});

-module.js(基本上每秒返回一条消息,持续5秒钟,然后退出)

var interval;
interval = setInterval(function(){
    console.log( 'module data' );
    if(interval._idleStart > 5000) clearInterval(interval);
}, 1000);
  • spawn() 子进程每1秒返回一条消息 module data,持续5秒,因为数据是“流式”的。
  • exec() 子进程在5秒后(进程关闭时)只返回一条消息:module data module data module data module data module data。这是因为数据是“缓冲”的。

请注意,无论是 spawn() 还是 exec() 子进程都不是设计用于运行 Node 模块的,这个示例只是为了展示它们之间的区别。(如果你想要运行 Node 模块作为子进程,请使用 fork() 方法。)


7
顺便提一下,避免使用 var spawn = spawn(...)var exec = exec(...) 这样的写法,因为这会覆盖函数。 - Remirror
如果设置了option.shell属性,spawn可以运行一个shell。请参见:https://nodejs.org/api/child_process.html#child_processspawncommand-args-options - MichaelMoser

30

一个很好的开始是阅读NodeJS 文档

关于'spawn',文档表明:

child_process.spawn()方法使用给定的命令生成一个新进程,并在args中传递命令行参数。如果省略,则args默认为空数组。

而对于'exec':

生成一个Shell,然后在该Shell中执行命令,缓冲所有生成的输出。 exec函数传递给命令字符串直接由shell处理,特殊字符(根据shell的不同)需要相应地处理。

主要问题似乎在于您是否需要处理命令的输出,这可能会影响性能(我还没有进行比较)。 如果您只关心进程完成,则应选择'exec'。 Spawn打开stdout和stderr的ondata事件流,而exec仅以字符串形式返回stdout和stderr的缓冲区。


26
这个答案的最后一行应该是:如果你只关心进程完成,那么'exec'将是你的选择。Spawn打开stdout和stderr流,并使用ondata事件,而exec只返回一个包含stdout和stderr字符串的缓冲区。 - anneb
8
我认为“NodeJS是一个很好的起点”这句话有争议。我刚开始学习,无法分辨其中的差异,一大堆文本让我感到很困难。我读到一段内容,向下滚动后就忘记了之前的内容。我知道RTFM(阅读完整手册)很重要,但手册应该更加易懂人性化才能得到广泛阅读。 - Marecky
3
同意@Marecky的观点。Nodejs文档就像一本词典:对于单个元素是很好的参考资料,但不太适合突出相似元素之间的差异。 - hraban

5

来自官方文档的一句话:

为了方便起见,child_process 模块提供了一些同步和异步的选项来替代 child_process.spawn()child_process.spawnSync()。每个选项都是基于 child_process.spawn()child_process.spawnSync() 实现的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接