为啥使用 OS 和磁盘缓冲区写入文件后读取操作更快?

Posted

技术标签:

【中文标题】为啥使用 OS 和磁盘缓冲区写入文件后读取操作更快?【英文标题】:Why are read operations much faster after writing files using OS and disk buffers?为什么使用 OS 和磁盘缓冲区写入文件后读取操作更快? 【发布时间】:2016-05-01 16:11:19 【问题描述】:

我正在使用CreateFile()WriteFile() 将大约一百个大小为50MB 的文件顺序写入我磁盘上的一个目录。在第二步中,使用CreateFile()ReadFile() 读取这些文件的内容。

我注意到一些部分奇怪的事情: 如果我在写入文件时通过FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,读取需要很长时间(通常为数百毫秒)。但是,当我不传递这些标志(而是使用 FlushFileBuffers())时,写入似乎以大致相同的速度发生,但在写入这些文件后读取它们的速度非常快(每个文件不到 20 毫秒!)。

这怎么可能?写入 5000MB 数据时传递的标志如何影响以后的读取?磁盘是否将整个 5GB 缓存在其缓存中?

【问题讨论】:

【参考方案1】:

当您传递FILE_FLAG_NO_BUFFERING 时,您是在告诉系统不要将数据放入其磁盘缓存中。那么当你读取数据时,系统必须从磁盘中获取数据。

当您省略FILE_FLAG_NO_BUFFERING 时,系统可以将数据放入其磁盘缓存中。所以后续读取数据时,可以直接从内存中读取,速度比磁盘快。

来自https://support.microsoft.com/en-us/kb/99794:

CreateFile() 的 FILE_FLAG_WRITE_THROUGH 标志会导致对该句柄的任何写入直接写入文件而不被缓冲。数据被缓存(存储在磁盘缓存中);但是,它仍然直接写入文件。此方法允许对该数据的读取操作以满足来自缓存数据的读取请求(如果它仍然存在),而不必执行文件读取来获取数据。在将数据写入文件之前,write 调用不会返回。这也适用于远程写入——网络重定向器将 FILE_FLAG_WRITE_THROUGH 标志传递给服务器,以便服务器知道在数据写入文件之前不满足写入请求。

FILE_FLAG_NO_BUFFERING 将这一概念更进一步,并消除了所有预读文件缓冲和磁盘缓存,从而保证所有读取都来自文件,而不是来自任何系统缓冲区或磁盘缓存。

您可能会感兴趣的 Raymond Chen 的这篇文章:We’re currently using FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH, but we would like our WriteFile to go even faster。摘录:

一位客户说他们程序的 I/O 模式是打开一个文件,然后 然后每隔一段时间将大约 100KB 的数据写入文件。他们是 当前使用 FILE_FLAG_NO_BUFFERING 和 FILE_FLAG_WRITE_THROUGH 标志打开文件,他们想知道他们还能做什么 让他们的写作速度更快。

嗯,一方面,你停止传递那两个标志!

这两个标志的组合基本上意味着“给我最慢的 可能的 I/O 性能!”因为它们强制所有 I/O 通过 立即使用物理媒体。

【讨论】:

这是否意味着 RAM 负载增加,因为 5GB 需要缓存在 RAM 中?在我的程序执行期间,我看不到 RAM 中有任何明显的变化。 你如何测量磁盘缓存使用了多少 RAM? 我使用默认的 Windows 性能监控工具来测量 RAM。如果缓存 5GB,我预计会看到一些差异。我刚刚编辑了我的问题以添加我在每次写入后使用FlushFileBuffers(),我想知道即使使用FlushFileBuffers(),Windows 是否仍会将这些文件保留在缓存中。 我认为我的回答是准确的。如果您让系统缓存数据,那么它可以更快地交付它。这就是缓存的用途。我不确定你想通过使用这些标志来实现什么。 我同意,我会接受你的回答,但使用FlushFileBuffers()后仍然无法解释提升。根据微软的说法:“系统文件缓存中的文件数据以操作系统确定的时间间隔写入磁盘,并释放该文件数据先前使用的内存——这被称为刷新缓存。[... ] 进程还可以通过调用 FlushFileBuffers 函数来强制刷新它打开的文件。”我是不是误会了什么?我哪里错了?

以上是关于为啥使用 OS 和磁盘缓冲区写入文件后读取操作更快?的主要内容,如果未能解决你的问题,请参考以下文章

缓冲文件(用于更快的磁盘访问)

Go-文件目录操作分类详解(创建打开关闭读取写入判断等)

在磁盘上读取/写入文件时如何限制硬盘 I/O?

kafka基础

3 Python os 文件和目录

part12:Python 文件I/O(pathlib模块:PurePathPath,os.path,fnmatch,open,with,linecache,os模块操作文件和目录,tempfile(