我已经为 Windows 7 - 64 位编写了一个 C/C++ 程序,可以处理非常大的文件。在最后一步,它从输入文件 (10GB+) 中读取行并将它们写入输出文件。对输入文件的访问是随机的,写入是顺序的。 编辑:采用这种方法的主要原因是减少 RAM 使用量。
我在阅读部分基本上做的是:(抱歉,非常短,可能有错误)
void seekAndGetLine(char* line, size_t lineSize, off64_t pos, FILE* filePointer){
fseeko64(filePointer, pos, ios_base::beg);
fgets(line, lineSize, filePointer);
}
通常这段代码很好,不是说快,但在一些非常特殊的情况下它会变得很慢。该行为似乎不是确定性的,因为性能下降发生在文件其他部分的不同机器上,甚至根本没有发生。甚至走得太远,程序完全停止读取,同时没有磁盘操作。
另一个症状似乎是使用过的 RAM。我的进程保持它的 RAM 稳定,但系统使用的 RAM 有时会变得非常大。在使用了一些 RAM-Tools 之后,我发现 Windows 映射文件增长到几个 GB。这种行为似乎也取决于硬件,因为它发生在流程不同部分的不同机器上。
据我所知,这个问题在SSD上是不存在的,所以肯定和HDD的响应时间有关。
我的猜测是 Windows 缓存以某种方式变得“奇怪”。只要缓存正常工作,程序就会很快。但是当缓存出错时,行为要么进入“停止读取”要么进入“增加缓存大小”,有时甚至两者兼而有之。由于我不是 Windows 缓存算法方面的专家,我很乐意听到解释。另外,有什么方法可以让 Windows 脱离 C/C++ 来操作/停止/强制执行缓存。
由于我一直在寻找这个问题,所以我已经尝试了一些技巧,但没有成功:
- filePointer = fopen(文件名, "rbR");//只是填充缓存直到RAM已满
- 大量缓冲读/写,以阻止两者相互影响
提前致谢
最佳答案
真正随机访问一个巨大的文件是任何缓存算法最糟糕的情况。 可能最好关闭尽可能多的缓存。
有多个级别的缓存:
- CRT 库(因为您使用的是 f- 函数)
- 操作系统和文件系统
- 可能在驱动器本身上
如果您通过 CRT 中的 f- 函数将 I/O 调用替换为 Windows API 中的类似函数(例如,CreateFile、ReadFile 等),则可以消除 CRT 缓存,这可能会造成更大的危害比好。您还可以警告操作系统您将进行随机访问,这会影响其缓存策略。查看 FILE_FLAG_RANDOM_ACCESS
等选项可能还有 FILE_FLAG_NO_BUFFERING
.
您需要进行试验和测量。
您可能还需要重新考虑您的算法是如何工作的。搜索真的是随机的吗?您能否对它们重新排序,也许是分批处理,以便它们按顺序排列?您能否一次限制对文件中相对较小区域的访问?您能否将大文件分解成较小的文件,然后一次处理一个文件?您是否检查过驱动器和特定文件的碎片级别?
关于c - 使用 fgets 随机读取非常大的文件似乎会使 Windows 缓存达到极限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10853371/