1

我已经为 Windows 7 - 64bit 编写了一个 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 工具后,我发现 Windows 映射文件会增长到几 GB。这种行为似乎也取决于硬件,因为它发生在进程不同部分的不同机器上。

据我所知,SSD上不存在这个问题,所以它肯定与HDD的响应时间有关。

我的猜测是 Windows 缓存变得“奇怪”。只要缓存起作用,程序就会很快。但是当缓存出错时,行为要么进入“停止读取”,要么进入“增加缓存大小”,有时甚至两者兼而有之。由于我不是 Windows 缓存算法的专家,我很乐意听到解释。此外,有什么方法可以让 Windows 脱离 C/C++ 来操作/停止/强制缓存。

由于我现在正在寻找这个问题一段时间,我已经尝试了一些技巧,但没有成功:

  • 文件指针 = fopen(文件名,“rbR”);//只是填充缓存直到RAM已满
  • 读/写的大量缓冲,以阻止两者相互进入

提前致谢

4

2 回答 2

3

对于任何缓存算法来说,真正随机访问一个巨大的文件是最坏的情况。最好尽可能多地关闭缓存

有多个级别的缓存:

  • CRT 库(因为您使用的是 f 函数)
  • 操作系统和文件系统
  • 可能在驱动器本身上

如果您通过 CRT 中的 f 函数将您的 I/O 调用替换为 Windows API 中的类似函数(例如,CreateFile、ReadFile 等),您可以消除 CRT 缓存,这可能弊大于利。您还可以警告操作系统您将进行随机访问,这会影响其缓存策略。请参阅类似FILE_FLAG_RANDOM_ACCESS和可能的选项FILE_FLAG_NO_BUFFERING

您需要进行实验和测量。

您可能还必须重新考虑您的算法是如何工作的。搜索真的是随机的吗?您能否重新排序它们,也许是分批,以便它们有序?您可以一次限制对文件相对较小区域的访问吗?你能把大文件分解成更小的文件,然后一次处理一个吗?您是否检查过驱动器和特定文件的碎片级别?

于 2012-06-01T16:56:30.007 回答
3

根据您的应用程序的整体情况,您可能会采取不同的方法 - 可能是这样的:

  1. 决定您需要输入文件中的哪些行并将行号存储在列表中
  2. 对行号列表进行排序
  3. 按顺序读取输入文件一次,然后取出您需要的行(更好的是,寻找下一行并抓住它,特别是当有很大的差距时)
  4. 如果您抓取的行列表足够小,您可以将它们存储在内存中以便在输出之前重新排序,否则,将它们粘贴在一个较小的临时文件中,并使用该文件作为当前算法的输入,以重新排序最终输出的行

这绝对是一种更复杂的方法,但它对您的缓存子系统会更友好,因此可能会表现得更好。

于 2012-06-01T17:38:23.550 回答