对于node.js中的本地文件,我应该使用异步文件IO方法而不是同步方法吗?



我有一个非常简单的实用程序脚本,我用JavaScript为node.js写了一个读取文件,做一些计算,然后写一个输出文件。当前形式的源代码看起来像这样:

fs.readFile(inputPath, function (err, data) {
    if (err) throw err;
    // do something with the data
    fs.writeFile(outputPath, output, function (err) {
        if (err) throw err;
        console.log("File successfully written.");
    });
});

这很好,但是我想知道在这种情况下使用这些函数的同步变体是否有任何缺点,就像这样:

var data = fs.readFileSync(inputPath);
// do something with the data
fs.writeFileSync(outputPath, output);
console.log("File successfully written.");

对我来说,这比各种回调更容易阅读和理解。在这种情况下,是否有理由使用前一种方法?

我意识到对于我在本地运行的这个简单脚本,速度根本不是问题,但是我对理解它背后的理论很感兴趣。什么时候使用异步方法有帮助,什么时候没有帮助?即使在生产应用程序中,如果我只是读取一个文件,然后等待执行下一个任务,那么还有理由使用异步方法吗?

重要的是在同步IO发生时节点进程需要做什么ELSE。在由单个用户在命令行运行的简单shell脚本的情况下,同步IO完全可以,因为如果您正在执行异步IO,那么您所做的就是等待IO返回。

然而,在一个有多个用户的网络服务中,你永远不能使用任何同步IO调用(这是节点的全部意义,所以相信我的话)。这样做将导致所有连接的客户端停止处理,并且完全失败。

经验法则:shell脚本:OK,网络服务:禁止!

为了进一步阅读,我在这个回答中做了几个类比。

基本上,当节点在网络服务器上做异步IO时,它可以要求操作系统做很多事情:读一些文件,做一些数据库查询,发送一些网络流量,在等待异步IO准备好时,它可以在主事件线程中做内存/CPU的事情。使用这种架构,节点获得了相当好的性能/并发性。然而,当同步IO操作发生时,整个节点进程只是阻塞,什么也不做。它只是等待。无法接收到新的连接。没有处理发生,没有事件循环,没有回调,什么都没有。只有一个同步操作会使整个服务器为所有客户端停止运行。你绝对不能做这件事。不管它有多快或类似的东西。这与本地文件系统或网络请求无关。即使您为每个客户机花费10ms从磁盘读取一个小文件,如果您有100个客户机,客户机100将等待整整一秒钟,而客户机1-99一次读取一个文件。

异步代码不会阻塞执行流程,允许您的程序在等待操作完成时执行其他任务。

在第一个示例中,您的代码可以继续运行,而无需等待文件被写入。在第二个示例中,代码执行被"阻塞",直到文件被写入。这就是为什么同步代码被称为"阻塞",而异步代码被称为"非阻塞"。"