`fs.appendFile()`的原子性保证是什么?

时间:2017-06-09 18:10:17

标签: node.js

fs.appendFile()的文档在原子性保证方面含糊不清。

我特别想知道,如果在同一个文件上对数据进行两次或多次调用,而不等待回调,数据是否可能被交错或丢弃(例如由于写入重叠区域)之间。例如,请使用以下代码:

fs.writeFileSync('blort.bin', '');
for (let i = 0; i < 10; i++) {
  const data = Buffer.alloc(65536, i);
  fs.appendFile('blort.bin', data, () => {});
}

假设没有文件系统错误且没有其他进程写入有问题的文件,那么Node会在所有追加操作完成后做出以下保证吗?:

  • 文件大小正好是640k。
  • 该文件由10个64k数据块组成,每个数据统一包含一个字节值。

我也很好奇是否有任何序列化保证(尽管我没有假设)。也就是说,保证按顺序执行附加?

更新:补充说明这是代理该文件的唯一代码。

1 个答案:

答案 0 :(得分:0)

据我所知,您的附加内容将按顺序发生,除非另一个进程正在写入目标文件,否则不会覆盖现有数据。

Node是单线程的(从正在运行的应用程序的角度来看)并在内部对文件写入进行排队,因此如果您将1 23写入文件,该文件将包含123

Node确实会启动新线程来处理IO,但这是运行时的一项功能,对开发人员来说是隐藏的。

更新

在第一次阅读时,我错过了您的要求,即您的追加发生在多个回叫为空或无效的回叫中。

这极大地改变了事情。

如果您使用异步调用,例如fs.appendFile(),则必须提供必须检查错误的回调。如果您在不等待回调结束的情况下堆叠异步调用,无法保证您的写入将按顺序发生,或者不会覆盖以前的数据。

底线:如果没有经常检查错误的正确回调,请不要使用异步功能。

否则会破坏Node的事件驱动模型的整个想法。

我通常解释这一点的方法是考虑到,在异步调用中,由于包括cpu和IO负载在内的众多因素,无法预测何时会触发回调

如果您无法知道何时触发回调,则无法预测多个呼叫将按顺序运行。

更新2

要明确的是,如果不提供回调,则无法调用异步函数,并且可以保证任何预期的行为。

从事件方面考虑:

fs.appendFile()向IO线程添加事件处理程序,并将包含其参数的事件发送到IO线程。

操作完成后,将触发此事件处理程序,这是您的回调或将触发您的回调。

无需等待操作完成,您无法保证它已成功或已按预期完成。