许多小文件或一个大文件?(或者,打开和关闭文件句柄的开销)(C++)

dud*_*ico 17 c++ optimization file-io

我创建了一个执行以下操作的应用程序:

  1. 进行一些计算,计算出的数据写入文件 - 重复500,000次(总之,一个接一个地写入500,000个文件) - 重复2次(总共写入1.5 mil文件).
  2. 从文件中读取数据,使用文件中的数据进行一些密集计算 - 重复1,500,000次迭代(迭代在步骤1中写入的所有文件)
  3. 重复步骤2进行200次迭代.

每个文件大约212k,所以我有~300Gb的数据.在具有2.8 Ghz的Core 2 Duo CPU上看起来整个过程需要大约40天.

我的问题是(正如你可能猜到的)是完成整个过程所需的时间.所有计算都是串行的(每个计算都取决于之前的计算),因此我无法将此过程与不同的CPU或PC并行.我正在考虑如何使这个过程更有效率,我很确定大部分开销都用于文件系统访问(呃...).每次我访问文件时,我打开一个句柄,然后在我读完数据后关闭它.

我改善运行时间的一个想法是使用一个300Gb的大文件(或者每个50Gb的几个大文件),然后我只使用一个打开的文件句柄,只需查找每个相关数据并阅读它,但我这不是打开和关闭文件句柄的开销.有人可以对此有所了解吗?

我的另一个想法是尝试将文件分组到更大的~100Mb文件,然后我每次读取100Mb而不是多次212k读取,但这比上面的想法实现起来要复杂得多.

无论如何,如果有人可以给我一些建议或有任何想法如何改善运行时间我会很感激!

谢谢.

Profiler更新:

我在流程上运行了一个分析器,看起来计算占运行时间的62%,文件读取需要34%.这意味着,即使我奇迹般地将文件i/o成本降低了34倍,我仍然留下了24天,这是相当大的改进,但仍然很长时间:)

xto*_*ofl 12

打开文件句柄不太可能成为瓶颈; 实际的磁盘IO是.如果您可以并行化磁盘访问(例如使用多个磁盘,更快的磁盘,RAM磁盘......),您可能会受益更多.此外,确保IO不阻止应用程序:从磁盘读取,并在等待IO时进行处理.例如,带有阅读器和处理器线程.

另一件事:如果下一步取决于当前的计算,为什么要将其保存到磁盘呢?也许对于进程的依赖关系的另一种观点,你可以重做数据流并摆脱大量的IO.

哦,是的,测量它 :)


Mar*_*Ray 10

每个文件大约212k,所以我有~300Gb的数据.看起来整个过程需要大约40天......计算是串行的(每个计算都取决于之前的计算),所以我无法将此过程并行到不同的CPU或PC....非常确定大部分开销都用于文件系统访问...每次访问文件时,我都会打开一个句柄,然后在读完数据后关闭它.

连续写入数据300GB的数据可能需要40分钟,只有40天的一小部分.磁盘写入性能不应该是一个问题.

您只想打开一次文件的想法就是现货.在每次操作之后可能关闭文件会导致处理阻塞,直到磁盘完全写出所有数据,否定了磁盘缓存的好处.

我敢打赌,这个应用程序的最快实现将使用内存映射文件,所有现代操作系统都具备此功能.它最终也可能是最简单的代码.你需要一个64位处理器和操作系统,你应该不会需要的RAM 300GB.将整个文件一次映射到地址空间,然后使用指针读取和写入数据.


iai*_*ain 5

从您的简短解释来看,听起来 xtofl 线程建议是正确的方法。我建议您首先分析您的应用程序,以确保时间在 IO 和 cpu 之间分配。

然后我会考虑由两个队列连接的三个线程。

  1. 线程 1 读取文件并将其加载到 RAM 中,然后将数据/指针放入队列中。如果队列超过特定大小,线程将休眠,如果队列低于特定大小,则重新启动。
  2. 线程2从队列中读取数据并进行计算,然后将数据写入第二个队列
  3. 线程3读取第二个队列并将数据写入磁盘

您可以考虑合并线程 1 和 3,这可能会减少磁盘争用,因为您的应用程序一次只会执行一个磁盘操作。

另外操作系统如何处理所有文件?它们都在一个目录中吗?当您浏览目录(gui filemanager/dir/ls)时,性能如何?如果此性能很差,您可能会在文件系统舒适区之外工作。虽然您只能在 UNIX 上更改此设置,但某些文件系统针对不同类型的文件使用进行了优化,例如大文件、大量小文件等。您还可以考虑将文件拆分到不同的目录中。