C++ 使用内存中的文件

C++ 使用内存中的文件,c++,c,caching,memory-management,C++,C,Caching,Memory Management,据我所知,如果我们加载任何文件一次进行读取,那么它将按照LRU algo保持在RAM中,直到没有被其他文件交换 在我的C程序中,我正在加载124MB文本文件以读取其内容。理想情况下,一旦我执行它应该在RAM中,下次当我执行相同的程序时,它应该只从RAM中获取它 但在这里,这两种情况下所用的时间都是15s,与我执行同一程序的时间无关 由于缓存大小非常有限,如3MB,因此无法将其放入缓存中 为了加快程序的执行,还有什么其他的替代方法 更新: 代码链接: -此文件包含main()类并执行分类作业 -此

据我所知,如果我们加载任何文件一次进行读取,那么它将按照LRU algo保持在RAM中,直到没有被其他文件交换

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

但在这里,这两种情况下所用的时间都是15s,与我执行同一程序的时间无关

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

为了加快程序的执行,还有什么其他的替代方法

更新:

代码链接:

-此文件包含main()类并执行分类作业


-此文件包含用于读取文件和执行分类的功能

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

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


在这篇小文章中可以找到更多的信息:

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

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


在这篇小文章中可以找到更多信息:

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

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

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

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

您可能不喜欢这一点,原因如下:

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

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

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

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

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

您可能不喜欢这一点,原因如下:

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

在一个像样的SSD上加载一个120MB的文件应该不到1秒。对于硬盘驱动器,2-3秒。我可以假设您不以大块方式读取文件,而是使用标准库中的函数(例如
fscanf
或使用
fstream
)以小增量读取文件

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

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

编辑: 大量调用
fscanf
get
。尝试将整个文件读入一个缓冲区,然后使用该缓冲区。使用
read
(而不是
fread
)一次性读取文件

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

Edit2

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


如果您不知道这些函数中的任何一个,请尝试用谷歌搜索
manfuncname
。例如,
manstrktok

在一个像样的SSD上加载一个120MB的文件应该不到1秒。对于硬盘驱动器,2-3秒。我可以假设您不以大块方式读取文件,而是使用标准库中的函数(例如
fscanf
或使用
fstream
)以小增量读取文件

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

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

编辑: 大量调用
fscanf
get
。尝试将整个文件读入一个缓冲区,然后使用该缓冲区。使用
read
(而不是
fread
)一次性读取文件

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

Edit2

在函数
read\u model
中,将
fscanf
替换为
sscanf
,以处理缓冲区。
一次性将所有模型读取到文件大小的大缓冲区。可以使用
stat
找到文件大小。不要使用
fgets
而是使用
strtok
迭代缓冲区。后者可以
$ 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