在Linux中无需磁盘缓存读取文件

13
我有一个C程序,每周运行一次,仅读取大量文件一次。由于Linux也会缓存所有被读取的内容,它们会不必要地填充缓存,这会严重拖慢系统的速度,除非它有SSD驱动器。
那么,如何在不填充磁盘缓存的情况下打开和读取文件?
注意:所谓磁盘缓存是指当您第二次读取文件时,它从RAM而不是磁盘中读取。即从磁盘读取的数据留存在RAM中,因此对同一文件的后续读取将不需要重新从磁盘读取数据。

你会认为Linux会有关于磁盘缓存的一些配置。但不管怎样,这真的是一个C语言的问题吗?无论使用哪种编程语言,您都可能遇到同样的问题,是吗?您是否尝试在valgrind中运行程序?可能是因为您有内存泄漏。 - autistic
1
没错,不过否则就可能会有人发布Python代码示例 :) - sashoalm
好的,如果你没有要求使用C语言,你可能会得到更多关于“Linux”的答案。请回答我所有的问题:你尝试过在valgrind中运行你的程序吗? - autistic
好的,我已经移除了 C 标签。 - sashoalm
2个回答

10
我相信将O_DIRECT传递给open()应该会有所帮助:

O_DIRECT(自Linux 2.4.10起)

尝试最小化对此文件的I/O的缓存效果。一般来说,这会降低性能,但在特殊情况下很有用,例如当应用程序进行自己的缓存时。文件I/O直接完成到/从用户空间缓冲区。仅使用O_DIRECT标志会尝试同步传输数据,但不提供O_SYNC的数据和必要元数据传输的保证。为了保证同步I/O,必须除O_DIRECT外还要使用O_SYNC。

man page底部有关于O_DIRECT的进一步详细说明,其中包括Linus的有趣引用语。


2
只是为了确认一下,因为它说“通常这会降低性能”- 它不会真的降低我的性能,对吧?因为我确实只读取文件一次。 - sashoalm
@sashoalm:我认为这正是它的意思。它会降低重复读取的性能。然而,由于您不进行重复读取,这对您不适用。如果有什么问题,在您的情况下,它应该会提高性能,因为您不会不必要地污染缓存。 - NPE
4
如果我没记错的话,这将禁用预读取,这很可能是性能下降的原因所在。 - Hasturkun
1
确实。没有缓存意味着如果您按字符读取,那么驱动器将为每个字符寻找一次,而不是为4KB寻找一次,这意味着需要寻找的次数增加了4096倍。我认为这不是OP想要的。 - autistic
10
@modifiablelvalue说得不完全正确:使用O_DIRECT甚至无法读取一个字符。这在我链接的手册中有详细说明。举一个例子:在Linux 2.4下,数据传输大小、用户缓冲区的对齐方式以及文件偏移量都必须是文件系统逻辑块大小的倍数。在Linux 2.6下,对齐到512字节边界就足够了。 - NPE
请注意,如果没有使用O_DIRECT标志的其他进程读取相同的文件,则使用O_DIRECT将降低性能。在这种情况下,两个读取器都会受到性能惩罚。如果您确实知道没有其他进程正在读取这些文件,并且您只需要读取一次文件,则O_DIRECT可能是一个不错的解决方案。 - Mikko Rantalainen

6
你可以使用posix_fadvise()函数并传入POSIX_FADV_DONTNEED参数,请求系统释放已经读取过的页面。

2
谢谢。POSIX_FADV_NOREUSE会更合适吗?我刚看了一下链接。 - sashoalm
4
可能会有作用,但文档表明它是一个无操作。 - Hasturkun
我更喜欢使用fadvise而不是O_DIRECT。你甚至可以有另一个程序定期告诉系统它不需要缓存某些文件。当使用awstats解析大型日志文件时,我就是这样做的。 - Marki555
3
在读取数据之前,您可以使用POSIX_FADV_NOREUSE来提高性能,而在读取后使用POSIX_FADV_DONTNEED来释放已读取的数据。目前,POSIX_FADV_NOREUSE不执行任何操作,但也许某天会被实现。 - lav
正如 https://github.com/jborg/attic/issues/252 中所建议的那样,Linux 中的当前实现将无条件地清除缓存页面,可能会降低使用相同文件的其他应用程序的性能。 - jan

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