用C ++读/写文件的快速跨平台算法

时间:2010-01-26 00:29:51

标签: c++ stl file-io cross-platform memory-mapped-files

我想提出一个看似简单的问题,我无法找到答案。 是否有 FAST 现代算法用于文件输入和/或输出,可以使用所有符合标准的C ++编译器进行编译,适用于所有操作系统而无需外部库?

  1. 我发现最快的方法是使用内存映射文件,但这不会导致我们想要在所有平台上运行相同的代码
  2. 我们不能使用像Win32 API这样的api,因为它会使它特定于平台
  3. 我不想使用c,我希望算法只是带有stl的纯c ++代码(如果可行的话),而不是一些丑陋的c与混合的asm hack / trick
  4. 不属于标准c ++的框架或外部库不应该像wxWidgets,Qt,MFC等一样使用。
  5. 这整个问题的最大优点是算法尽可能 FAST ,这与使用内存映射文件的速度一致,甚至更快但是我知道这是不可能的
  6. 除了我之外,你有没有看过其他人研究过的东西? 这样的算法甚至可能吗?

    感谢您的任何建议

7 个答案:

答案 0 :(得分:9)

具有以下限制:

  

可以使用所有符合标准的C ++编译器进行编译,适用于所有操作系统而无需外部库吗?

您几乎限制自己使用标准库文件IO功能。也许POSIX函数(取决于你正在考虑的“所有符合标准的C ++编译器”的子集)。

如果它们不够快,你将不得不开始放弃一些限制。

答案 1 :(得分:9)

这与“算法”无关。

当谈到将数据写入文件时,你受操作系统的支配 - 内存映射文件“快速”,因为你只是写入内存,而操作系统将其同步回来自己的时间。如果操作系统不支持它,那么你就不幸了 - 除非你想要实现自己的内存映射层。

顺便提一下,POSIX有mmap,所以如果你限制自己使用POSIX兼容系统,你就可以了。

答案 2 :(得分:4)

为了对“操作系统的怜悯”提出另一种观点,复制文件的大部分开销都在于操作系统。碎片文件比读取碎片整理的文件需要更多时间来读取。没有用于检测碎片文件的通用或标准C ++函数。

C ++中最快的方法:

std::ifstream in_file;
std::ofstream out_file;

out_file << in_file.rdbuf();

您可以在网上搜索关键字“ copy file rdbuf ”来查找更多详细信息。上面的片段将复制留给操作系统,但可以在所有平台上移植。通过读入C ++ i / o流,您可以设置读取缓冲区的大小,或者让它使用您自己的缓冲区。

更快的文件复制需要特定于平台的功能,例如DMA传输。使用线程和多次缓冲可以加快速度;但C ++不支持线程(有一个事实上的标准,POSIX,它支持线程)。一个线程将读入缓冲区,而另一个线程从缓冲区写入。

答案 3 :(得分:2)

有些观点:

  • 这与算法无关。
  • 想要定位所有操作系统并不是一个非常有成效的目标(而且这是不可能的)
  • 在您对代码进行测试之前,您的代码无法在特定平台上运行。相反,我会专注于一些可行的操作系统 - 比如POSIX + Win32。
  • 在这种情况下,你可以进行内存映射,例如通过为Windows实现mmap()(在MapViewOfFile()等之上 - 如果你需要一些灵感,git源代码有一个Windows的mmap实现)
  • 如果你不能使用内存映射,我建议使用普通的C文件api而不是C ++的文件流,如果性能是一个大问题。尽管C ++的流有可能在某些操作中具有更高的性能,但实际上它的速度要慢得多。
  • 但是,为了获得良好的性能,它通常可以“足够好”,只是为了确保您以理智的方式处理数据。顺序读取数据,不重读等。完美是善的敌人;)

答案 4 :(得分:1)

在文件系统块大小的倍数(或2的幂)的块中顺序读取可能会有所帮助。然后,一旦块在内存中,就将数据分开。在某个地方有一张白皮书,他们测试了各种块大小的性能。我希望我能再次找到它。

您也可以尝试使用专用线程从文件中读取块,而另一个用于在内存中执行数据操作(当然,使用适当的同步)。这允许您在阻止文件读取调用时使用CPU处理数据。

无论如何,如果您尝试这些想法,如果您发现不同,请告诉我们。基准测试的实际结果很有意思。

答案 5 :(得分:1)

快速IO通常归结为两件事:

  1. 尽量减少数据复制
  2. 最小化内核/用户上下文切换
  3. 大多数IO技术都尝试解决其中一种问题。我所知道的最快的跨平台IO代码是Perl IO系统。我建议看看the source。 Perl黑客已经花了数十年时间尽可能快地在尽可能多的平台上获得IO。

答案 6 :(得分:0)

其他海报是正确的,因为性能总是与通用性(跨平台)不一致。

但是,一般情况下,通过“缓冲”输入来获得最佳效果 - 使用fread()读取相对较大的数据块并进行处理。

我知道这是一个非常基本和一般性的答案,但这与您可以获得的具体情况相比,没有更具体的平台,或者更多地了解您正在处理的特定输入。