2010-01-26 105 views
5

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

  1. 我发现,最快的方法就是使用内存映射文件,但不会做的原因,我们希望在所有平台上的工作
  2. 我们不能使用API​​,如Win32 API中的同一段代码因为这将使它具体的平台
  3. 我不想使用c,我希望算法只是纯粹的C++代码与STL如果可行的话,不是一些丑陋的c与混合asm hack/trick
  4. 框架或外部不属于标准C++的库不应该像wxWidgets,Qt,MFC等一样使用。
  5. 大这整个问题的empasis是,该算法是FAST成为可能,随着内存映射文件做它的速度线的东西,甚至更快的将是巨大的,但我知道这是不可能的

你有没有见过除我以外的其他人研究过的东西? 这样的算法甚至可能吗?

感谢您的任何建议

回答

9

有以下限制:

可以与所有符合标准的C++编译器进行编译,并适用于所有的操作系​​统无需外部库的要求?

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

如果他们对你来说不够快,你将不得不放弃一些限制。

+1

同意。唯一的C++标准文件I/O来自标准库,即。头文件''或''。如果你想要快速的文件I/O,最重要的是**不**一次读取/写入一个字节的文件,而是一次读取/写入大块。 – stakx 2010-01-26 00:47:10

+0

可以用iostream一次读取整个文件吗?那会提供性能优势,我不这么认为?不是cstdio的c头? – user258883 2010-01-26 01:02:51

+2

一次读取整个文件仍然比映射到内存慢。 – 2010-01-26 01:11:35

9

这与“算法”无关。

当涉及到将数据写入文件时,您处于操作系统的摆布之中 - 内存映射文件是“快速”的,因为您只是写入内存,并且操作系统会同步回到内存它自己的时间。如果操作系统不支持它,那么在这方面你就不太好运 - 除非你想实现你自己的内存映射层。

顺便说一句,POSIX有mmap,所以如果你限制自己POSIX兼容系统,你没事。

2

几点:

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

@kusma:我很想看看C的'stdio'和C++的'iostream'功能之间的性能比较。你有没有可能将我指向这些资源?因为我曾经看过C++'iostream'库源代码(更具体地说,是MinGW附带的实现),并且有一种印象,即它实际上只是一个非常简单(基于模板)的C文件I/O功能。因此,我不希望看到任何显着的表现差异。 – stakx 2010-01-26 00:51:13

+0

上帝的敌人? Yikes ... :) – 2010-01-26 01:12:17

+0

stakx:不幸的是,没有。结果很长一段时间没有了。在一位朋友报告使用std :: istream(与C API相比)的GCC/Linux显着减速之后,我在2001年左右做了一些关于MSVC的分析。 IIRC,我们都发现性能下降大致相同,约为30%。不过,这可能是记忆让我误解了数字。 德鲁:对不起,我的意思是“撒旦的敌人”,当然;) – kusma 2010-01-26 01:46:49

0

其他海报是正确的,因为性能总是与通用性(跨平台)不一致。但是,通常情况下,您可以通过“缓冲”输入来获得最佳结果 - 使用fread()读取相对较大的数据块并处理这些数据。

我知道这是一个非常基本的和一般的答案,但这是关于具体的,因为您可以得到没有更具体的平台特定,或更多地了解您正在处理的特定输入。

1

按照文件系统块大小的倍数(或幂次方)的顺序读取可能会有所帮助。然后在块存储在内存时挑选数据。他们在某处测试了各种块大小的性能。我希望我能再次找到它。

你也可以尝试拥有一个专用线程来读取文件中的数据块,另一个数据操作在内存中进行(当然还有正确的同步)。这允许您在阻止文件读取调用时使用CPU来处理数据。

无论如何,如果你给这些想法一个尝试,请让我们知道,如果你注意到一个区别。您的基准测试的实际结果会很有趣。

+0

大多数硬盘使用的块大小是512字节的倍数。对于较大的硬盘,它可能是1024或更大。 – 2010-01-26 17:50:15

+0

上面/下面的层使用的缓冲区大小可能与文件系统不同。尝试不同的2的幂(不要把自己限制在512/1024,一直到256kiB)。我记得4kiB是在Linux的其中一个层中使用的魔术数字,但我不记得在哪里。对不起,我不能更具体。 – 2010-01-26 18:18:32

+0

4k是文件系统块的默认大小。 – 2010-01-26 19:59:52

1

快速IO一般可以归结为两点:

  1. 最大限度地减少数据复制
  2. 最小化内核/用户上下文切换

最重要IO技术,试图解决一个或另一个。 IO知道的最快的跨平台代码是Perl IO系统。我建议看看the source。 Perl黑客已经花了数十年在尽可能多的平台上尽可能快地获得他们的IO。

4

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

在C++中的最快方法:

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

out_file << in_file.rdbuf(); 

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

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