async.waterfall 和 child_process.execSync 有啥区别?

Posted

技术标签:

【中文标题】async.waterfall 和 child_process.execSync 有啥区别?【英文标题】:What's the difference between async.waterfall and child_process.execSync?async.waterfall 和 child_process.execSync 有什么区别? 【发布时间】:2016-10-06 11:45:57 【问题描述】:

说如果这是linux shell,我想做的是:

copy file1 tmp
rename tmp file2

我可以做瀑布

function copyFile(cb) 
    child_process.exec('cp file1 tmp', function (error, stdout, stderr) 
        ......
    );

async.waterfall([
    copyFile,
    renameFile
], function (error) 
    if (error) 
        //handle readFile error or processFile error here
    
);

或者猜猜我能做到

child_process.execSync('cp file1 tmp");
child_process.execSync('rename tmp file2');

请问有什么区别?例如性能?阻塞? 非常感谢!

【问题讨论】:

结果和你已经知道的一样,但是 1. version 是异步 IO 风格,最适合 Node.js,从性能角度来看应该更好,但是 2. version 更具可读性@ 987654321@ 对于版本 1,它会创建一个单独的进程吗? 没错,child_process.exec 总是在创建进程。 实际上我的问题是:瀑布也创建子进程?我猜是这样的。 async.waterfall不会自己创建进程,但是如果你在里面使用child_process.exec,它会在执行过程中创建进程。 【参考方案1】:

这里的主要区别是execSync 是阻塞的,exec 是非阻塞的。 execSync 阻止创建过程,直到使用 execSync 创建的 child_process 返回。 exec 立即返回,如果以后有一个值,将返回一个值,并且不会阻止创建父进程。否则,它们在阻塞之外的行为是相同的。

async.waterfall 是一种控制流机制,它只保证操作按顺序执行,并将返回值从链中的第一个函数链接到链中的最后一个函数。如果传递给async.waterfall 的函数之一包含会阻塞的代码,那么async.waterfall 也会被阻塞。 async.waterfall 不保证在其中执行的所有代码都是异步的。

使用child_process 意味着这将在一个单独的进程上执行,而不是在使用node 执行的主进程上。您不应该将child_process 用于控制流,因为创建和销毁新的子进程会产生开销。除非您正在执行一些 CPU 密集型任务或需要单独的进程,否则您应该避免这种情况。

如果您想同步执行事情,您可以将所有代码包装在 try/catch 块中,但我肯定会说不要将 child_process 用于控制流。

从性能的角度来看,这两种方法都不好,因为它们创建了一个 child_process,但是exec() 会更好,因为它至少会立即返回到创建过程,从而允许其他代码继续执行。每当在 Node 中使用阻塞代码时,您都会消除使用 Node 的主要好处。在某些情况下需要阻塞,例如需要模块,但在大多数情况下,有一个非阻塞的替代方案。

顺便说一句,如果您尝试复制文件,您可以使用fs 模块并将原始文件通过管道传输到具有新名称的新目标中的新文件中。以下方法是异步的,不需要任何外部依赖项或控制流库。此外,它应该比您在上面实现的任何代码都具有更高的性能。

var fs = require('fs');

function copy (src, dest, callback) 
    var r = fs.createReadStream(src);
    var w = fs.createWriteStream(dest);

    r.pipe(w);

    r.on('error', function() 
        return callback(err);
    );

    r.once('end', function() 
        return callback();
    );

【讨论】:

非常感谢您提供详细信息。所以你认为 try/catch 是对抗 async/child_process 的最佳方法,你能写一些代码来演示它吗? (我选择了文件副本作为示例,实际上它是其他命令,因此 createReadStream 将不适用)非常感谢! @user3552178 你想做什么你不想使用非阻塞方法? 如果我理解正确,您认为 child_process.exec() 在我的情况下比 async 更好吗?如果是这样,我很好。我只是不知道如何在这种情况下为“如果您想同步执行事物,您可以将所有代码包装在 try/catch 块中”编写代码。我的问题可能令人困惑,因为我需要消化你告诉我的内容,:) 谢谢! @user3552178 我是说如果传入执行的代码是非阻塞的,async 会更好。您应该始终避免使用child_process,除非由于与创建新进程相关的开销而绝对必要。在节点中,try/catch 块总是同步执行,所以如果你有一堆你想同步执行的语句,你可以简单地做try // do whatever you need in here catch(err) console.log(err); 不知道你想要实际执行的场景我无法创建一个更好的例子不止于此。 在我的情况下,第 2 步需要等待第 1 步的结果,所以猜测它是阻塞的。谢谢!

以上是关于async.waterfall 和 child_process.execSync 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

async.waterfall 和 child_process.execSync 有啥区别?

async.waterfall

Node.js 中 For 循环中的 async.waterfall

Node.js 中 For 循环中的 async.waterfall

async.series / async.waterfall在post方法中有效吗?

for 循环内的 async.waterfall 转义 for 循环