file.flush()到底是做什么的?

179
我在Python的File Objects文档中找到了这段内容:

flush()函数不一定将文件数据写入磁盘。使用flush()后跟os.fsync()可以确保此行为。

所以我的问题是:Python的flush究竟是做什么的?我原以为它会强制将数据写入磁盘,但现在看来它并没有这样做。为什么呢?
4个回答

284

通常情况下,涉及两个级别的缓冲:

  1. 内部缓冲
  2. 操作系统缓冲

内部缓冲是由您所编写程序所使用的运行时/库/语言创建的缓冲区,旨在通过避免每次写入都进行系统调用来加速处理速度。因此,当您向文件对象写入内容时,实际上是将其写入缓冲区中,只有当缓冲区被填满时,才会使用系统调用将数据写入实际文件。

然而,由于操作系统缓冲的存在,这并不意味着数据已被写入磁盘。它可能只是从您运行时维护的缓冲区复制到操作系统维护的缓冲区。

如果您写入的内容仅停留在缓冲区中,当您的计算机断电时,该数据将不会保存到磁盘上。

因此,为了解决这个问题,您需要对相应对象使用flushfsync方法。

其中,flush方法将简单地将任何滞留在程序缓冲区中的数据写入实际文件。通常意味着数据将从程序缓冲区复制到操作系统缓冲区。

具体来说,这意味着如果另一个进程正在读取同一文件,它将能够访问您刚刚将数据刷新到文件中。然而,这并不一定意味着数据已经被"永久"存储在磁盘上。

为了实现这一点,您需要调用os.fsync方法,该方法确保所有操作系统缓冲区与其所属的存储设备进行同步,换句话说,该方法将把数据从操作系统缓冲区复制到磁盘。

通常情况下,您不需要使用任何一种方法,但是如果您担心什么内容实际上已经保存到磁盘上,那么请按照说明调用两个方法。


2018年补充说明。

请注意,带有缓存机制的磁盘现在比2013年更常见,因此现在涉及的缓存和缓冲区级别更多。我 假设 这些缓冲区也将由同步/刷新调用处理,但我不太确定。


15
当我使用 with file('blah') as fd: #dostuff 结构时,我知道它保证关闭文件描述符。那么它是否也会刷新或同步? - Marcin
6
它可以清空,但不会同步。 - Alex I
10
fsync对于原子性是必要的。如果没有在关闭文件、重新打开文件之前加入fsync,你不能指望找到你的内容。尽管它通常有效,但在使用linux系统的ext4文件系统和默认挂载选项时并不总是有效。另外,fsync不能保证真正磁铁翻转盘片,因为1:fsync可以被禁用(通过笔记本电脑模式),2:硬盘内部缓存可能没有被要求刷新。 - v.oddou
1
有没有办法清空操作系统的缓冲区,如果文件是由另一个进程写入的? - Nacht
2
fsync是*相对昂贵的。通常情况下,您不会编写需要100% ACID合规性和磁盘访问耐久性的关键任务软件,如果确实需要,则可能已经痛苦地意识到并应该知道可以采取哪些措施来获得这些保证。调用fsync将等待物理磁盘访问以将数据写入磁盘,而刷新和关闭仅等待数据移动到缓存内存。速度差异可能是几个数量级。 - Lasse V. Karlsen
显示剩余4条评论

13

由于操作系统可能不会这样做,所以需要执行刷新操作。刷新操作将文件数据强制写入到RAM中的文件缓存中,然后由操作系统实际将其发送到磁盘。


6
你说得对,但是“actually”在这里是相对的:如果目标设备启用了写缓存,当os.fsync()返回时,数据可能还没有到达实际的盘片/芯片。 - Frédéric Hamidi

9
它刷新了内部缓冲区,这应该会导致操作系统将缓冲区写入文件。Python使用操作系统的默认缓冲方式,除非您进行配置以更改其行为。
但有时操作系统仍然选择不合作,特别是在Windows/NTFS中存在写延迟等问题时。基本上,内部缓冲区已被刷新,但操作系统缓冲区仍然保持着它。因此,在这些情况下,您必须使用os.fsync()告诉操作系统将其写入磁盘。
[1] http://docs.python.org/library/stdtypes.html

0

基本上,flush() 函数可以清空你的 RAM 缓冲区,它的真正作用在于让你在后面继续向缓冲区写入数据 - 但不应该认为这是最好/最安全的写入文件功能。它只是为了让更多的数据进来而清空你的 RAM 缓冲区而已。如果你确保数据被安全地写入文件,那么就应该使用 close() 函数。


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