使用内存文件

Posted

技术标签:

【中文标题】使用内存文件【英文标题】:Working with in memory file 【发布时间】:2014-09-29 12:41:26 【问题描述】:

据我了解,如果我们加载任何文件一次以供读取,则它会按照根据 LRU 算法保留在 RAM 中,直到不会被其他文件交换。

在我的 C 程序 中,我正在加载 124MB 文本文件以读取其内容。理想情况下,一旦我执行它应该在 RAM 中,下次当我很快执行相同的程序时,它应该只从 RAM 中获取。

但这两种情况下的时间都只有15s,与我执行同一个程序的时间无关。

由于缓存大小非常有限,例如 3MB,因此无法放入缓存中。

还有什么其他的方法可以加快程序的执行速度?

更新:

代码链接:

http://webdocs.cs.ualberta.ca/~sajib/cmput606/project/code/svm_classify.c - 此文件包含 main() 类并执行分类工作

http://webdocs.cs.ualberta.ca/~sajib/cmput606/project/code/svm_common.c - 此文件包含用于读取文件和执行分类的功能

【问题讨论】:

不要多次运行您的程序。也许你可以使用循环? 哪个缓存?您是否真的在第一次运行中使用了第二次所需的所有数据,还是跳过了它?另外,你确定第一个是冷跑吗? @KerrekSB:每次用户输入时,我的流程都不同。所以不能把它放在循环中 @Deduplicator:是的,我必须在第一次运行以及每次运行中使用所有数据。因为是SVMrank训练好的分类文件,用来对输入文本进行分类 【参考方案1】:

一旦您的文件被第一次读取,在正常配置的操作系统下,所涉及的磁盘页面很可能会被有效缓存。

假设其他进程不需要此内存,第二次读取将比第一次快得多。

作为快速测试,我们生成一个随机文件并计算两次 md5sum(Linux 中的示例):

$ dd if=/dev/urandom of=/tmp/readtest count=124 bs=1M

$ echo 3 > /proc/sys/vm/drop_caches  # needs to be run as root

$ time md5sum /tmp/readtest 
f788abe8a8d120a87bb293e65e5d50ff  /tmp/readtest

real    0m5.706s
user    0m0.332s
sys 0m0.072s

$ time md5sum /tmp/readtest 
f788abe8a8d120a87bb293e65e5d50ff  /tmp/readtest

real    0m0.295s
user    0m0.268s
sys 0m0.024s

在删除缓存页面后观察巨大的差异。

您可能不欣赏这一点是有原因的:

当您第一次读取文件时,该文件实际上已被缓存(很可能) 此磁盘或分区禁用缓存,或文件系统/设备不支持缓存(极不可能)。

【讨论】:

是的,非常感谢这些努力。即使我测试了你的代码。正如您所描述的那样,它确实在起作用。在我的情况下,我什至期待类似的行为,但它让我在过去 3-4 天感到痛苦 这是我正在处理的包hlt.utdallas.edu/~altaf/cherrypicker.html,它在里面使用svmlight.joachims.org svm 分类器。下载后,只有一个命令可以测试它【参考方案2】:

在不错的 SSD 上加载一个 120MB 的文件需要不到 1 秒的时间。硬盘需要 2-3 秒。我可以假设您不会大块地读取文件,而是使用标准库中的函数(例如fscanf 或使用fstream)以小增量读取它。

尝试以大块 (1-16MB) 读取文件并在该缓冲区上进行处理。

如果有大量的 I/O 调用来读取文件,则会因从内核模式到用户模式来回切换以及其他请求 I/O 的进程而导致大量开销。

编辑:fscanfgets打了很多电话。尝试将整个文件读取到单个缓冲区并在该缓冲区上工作。使用read(不是fread)一次性读取文件。

如果文件太大,将其拆分为 1MB 读取。

编辑2

在函数 read_model 中,将 fscanf 替换为 sscanf 以处理缓冲区。 一次将所有模型读取到文件大小的大缓冲区中。可以使用stat 找到文件大小。而不是使用fgets 使用strtok 迭代缓冲区。后者可用于在迭代时用 NULL 字符替换新行。

如果您不知道这些功能中的任何一个,请尝试使用 Google 搜索 man funcname。例如。 man strktok.

【讨论】:

是的,我正在浏览开源代码 4 天。我已经添加了链接。如果你能看一下并提出我的任何建议,我真的很感激 非常感谢,我一遍又一遍地通过代码,我无法找到并决定在哪里以及如何决定读取缓冲区大小(以 1-16mb 为单位)。虽然你已经给出了这么多的细节,如果你指出我会很有帮助 查看更新的答案,如果这没有显着改善,然后运行分析器并查看代码停顿的位置。可能与文件读取无关。【参考方案3】:

如果您将文件作为一个整体读取,如果您的操作系统缓存了该文件,该文件将位于 RAM 中。如果在两次运行之间,缓存压力使您的操作系统(以 Linux 内核为例)丢弃了已加载的文件,您的文件将再次从磁盘读取它。

但是,您的程序无法控制文件是否来自缓存。操作系统为您的程序提供文件,无论是来自磁盘还是来自文件缓存,都超出了您的控制范围。

更多信息可以在这篇小文章中找到:Experiments and fun with the Linux disk cache

【讨论】:

以上是关于使用内存文件的主要内容,如果未能解决你的问题,请参考以下文章

内存映射文件的原子操作

在 C# 中使用内存映射文件时是不是可以避免数据副本?

如何使用 NAudio 将声音文件加载到内存中并稍后使用?

如何使用转储文件来诊断内存泄漏?

Linux中多个进程使用文件指针读取文件时是不是使用共享虚拟内存?

使用内存映射文件读取大文件