file.flush()是做什么的?
file.flush()是做什么的?
我在Python的文件对象文档中找到了这个内容:
flush()
并不一定将文件的数据写入磁盘。使用flush()
后跟os.fsync()
以确保这种行为。
所以我的问题是:Python的flush
到底做了什么?我以为它强制将数据写入磁盘,但现在我看到它并没有这样做。为什么?
《什么是file.flush()的作用?》
在文件操作中,通常涉及两个级别的缓冲:
1. 内部缓冲
2. 操作系统缓冲
内部缓冲是由你所使用的运行时库或语言创建的缓冲,它的目的是通过避免每次写入都进行系统调用来提高速度。当你向文件对象写入数据时,实际上是将数据写入到缓冲区中,当缓冲区填满时,数据才会使用系统调用写入到实际的文件中。
然而,由于操作系统的缓冲机制,这并不意味着数据已经被写入到磁盘上。它可能只是将数据从运行时维护的缓冲区复制到操作系统维护的缓冲区中。如果你写入的数据只停留在缓冲区中,而机器断电,那么当机器重新开机时,这些数据并不在磁盘上。
为了解决这个问题,你可以使用flush和fsync方法。
flush方法会将程序缓冲区中滞留的数据写入到实际的文件中。通常情况下,这意味着数据将从程序缓冲区复制到操作系统缓冲区。具体来说,如果另一个进程正在读取同一个文件,它将能够访问你刚刚刷新到文件中的数据。然而,这并不意味着数据已经“永久”存储在磁盘上。
要实现这一点,你需要调用os.fsync方法,该方法确保所有操作系统缓冲区与它们所属的存储设备同步,换句话说,该方法将数据从操作系统缓冲区复制到磁盘上。
通常情况下,你不需要担心这两个方法,但如果你在一个关于数据实际存储在磁盘上的场景中,你应该按照指示调用这两个方法。
补充(2018年):
请注意,现在缓存机制更为普遍,比2013年要多得多,因此涉及到更多级别的缓存和缓冲区。我假设这些缓冲区也会在同步/刷新调用时处理,但我并不确定。
在使用with file('blah') as fd: #dostuff这种构造时,我知道它保证关闭文件描述符。它也会刷新或同步吗?
:它会刷新,但不会同步。
fsync对于原子性是必需的。你不能期望关闭文件,重新打开它,然后在中间找到你关闭时的内容而没有fsync。它通常有效,但在使用Linux的ext4和默认挂载选项时不起作用。另外,fsync不能保证真正磁盘上的数据是否已被写入,因为1:fsync可以被禁用(由笔记本电脑模式),而2:硬盘的内部缓冲区可能不被指示刷新。
如果另一个进程写入文件,有没有办法刷新操作系统的缓冲区?
不清楚为什么Python关闭文件时不会同时调用fsync。在我看来,当你关闭文件时,你希望文件与关闭时的内容保存一致。fsync是否昂贵或是否有其他原因只进行刷新而不进行同步?
fsync相对来说是比较昂贵的。一般来说,你不会编写需要对磁盘访问进行100% ACID合规性和耐久性的关键软件,如果确实需要,你可能对此有深刻的认识,并且应该知道如何采取措施来获得这些保证。调用fsync将等待物理磁盘访问,将数据写入磁盘,而刷新和关闭仅等待数据被移动到缓存内存。速度差异可能相差数个数量级。
os.sync似乎只在Unix上可用。在Windows上,我对其他平台不了解。
在现代的Python 3文档中,我找不到关于file.flush()的任何信息,所以我认为调用file.flush()然后调用os.fsync()的建议已经不适用了,已经过时了。我曾经将这两个调用添加到一个数据记录脚本中,每10次f.write()迭代,结果即使在运行时按下Ctrl + C终止,它也只记录每10次f.write()的数据,尽管我每次迭代都调用f.write(),每10次迭代都调用f.flush + os.fsync()。所以,我不再使用这些调用。但是,f.close()仍然是明智的。