“flush”和“sync_all”有什么区别?

7

2
如果您不确定 sync_all() 的作用,那么几乎肯定不应该调用它,这只会减慢程序的速度而没有任何好处。(它的使用案例是实现具有精确数据耐久性保证的软件,如日志数据库。) 如果您在实际写入过程中使用了缓冲写入器,那么在写入结束时需要执行 flush() 操作。Bufwriter 通常会在关闭时执行 flush(),但这样无法报告错误,因此最好显式地执行 flush() - user4815162342
2个回答

5
TL;DR:如果您想“确保”数据已写入设备,则在使用File时使用File::sync_all。请注意,这并非必需。
FileWrite::flush 实现使用操作系统相关的 flush 操作,例如 std::sys::unix::File::flush 或者 std::sys::windows::File::flush。这些 flush 操作实际上什么也不做。两种实现都只返回 Ok(())

为什么?因为在两种情况下,write() 已经使用了底层的系统调用 write();Windows 上是基于句柄的写入,Unix-like 系统上是基于文件描述符的写入。此时,它已经超出了 Rust 环境的范畴,只剩下一个特定于文件的系统调用。

那么 什么是 Write::flush 有用的呢?如果你有任何类型的缓冲区实际文件之前,例如BufWriter,它就很有用。如果你有一个由BufWriter包装的File,那么你需要使用flush来确保字节被写入文件。虽然记住BufWriterDrop实现也尝试(!)写入这些字节很有用,但它可能会或可能不会工作,所以你应该在那里调用Write::flush(请参阅BufWriter的文档)。
话虽如此,sync_all并不是必需的,反而会阻塞程序。操作系统将处理文件系统同步。虽然你可以通过sync_datasync_all等待同步发生,但通常最好不要这样做。

3
虽然你的回答在技术上是正确的,但需要指出的是,如果提问者不知道sync_all()的作用,他们几乎肯定不想在写出随机文件后调用它。sync_all()并不能确保文件已经被写入底层硬件(操作系统会自动完成这个任务),它只会让你的程序_等待_直到完成。这只在非常特殊的情况下才需要使用。 - user4815162342
@user4815162342 不错的观点,这就是我使用关于“确保”的引号,但完全忘记将其添加到整个画面中。 - Zeta
我其实已经注意到并赞赏了关于“确保”的引用,只是我觉得对于原帖(和其他持有相同困惑的人)来说,可能还是太微妙了。感谢更新答案! - user4815162342
@user4815162342 不用担心,你完全正确地添加了评论,感谢你让我注意到它 :) - Zeta

4
在磁盘文件上,Write::flush 实际上是一个无操作(no-op)[source]。对于File来说是没有用的,只是为了保持一致性而实现。而这个接口是专门为那些在写入目标之前使用应用级别内存缓冲区的流设计的,正如文档中所述:

刷新此输出流,确保所有中间缓冲内容都到达它们的目标。

File::sync_dataFile有用版本的flush。在底层,内部缓冲区是在内核级别使用的,sync_data会委托给fdatasync POSIX调用,这就是flush在应用级别所做的事情。 File::sync_all 的作用类似于File::sync_data,并且还确保文件的元数据被写入磁盘。它在 POSIX 系统上委托给fsync
附注:根据系统的不同(例如 macOS、Android 等),File::sync_dataFile::sync_all 的实现可能完全相同。

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