C和C++中最快的文件输出方式

9
我正在帮助一个关于C语言输出问题的人,但我无法回答这个看似简单的问题。我想在我的答案中使用这个答案,那就是:

C / C++ 中最快的文件输出方式是什么?

我在使用C++和Java进行质数生成和数学算法优化方面做了很多工作,而这是我有时候遇到的最大障碍 - 我有时候需要快速地将很多数据移动到一个文件中。

如果这个问题已经有答案,请原谅我,但我已经在Google和SO上寻找了一段时间,但没有结果。

我不指望有人来做基准测试的工作 - 但有几种方法可以向文件写入数据,而我怀疑我并不知道全部。

所以总结一下,

在C和C++中有哪些输出到文件的方式?

这其中哪些是更快的?

显然从控制台重定向非常糟糕。 任何有关printfcoutfputc等的简短比较都会有所帮助。

编辑:

根据评论中的内容,

混合使用cout和printf实现更快的输出中有对cout和printf进行的优化基准测试。

这是一个很好的起点,但并不是我问的最好的答案。 例如,它没有处理评论中提到的std::ostreambuf_iterator<>,如果可能的话。它也没有处理fputc或者提及控制台重定向(相比之下有多糟糕)(不需要提到)。

编辑2:

此外,为了证明我的历史情况,您可以假设几乎无限量的数据输出(程序在较新的Intel i7上运行数天,产生几千兆字节的文本)。

临时存储在这里只能帮助一点 - 我意识到你不能轻松地缓存几千兆字节的数据。


1
你尝试过C++的std::ostreambuf_iterator<>吗? - user2033018
可能是混合使用cout和printf以实现更快的输出的重复问题。 - cbr
1
试试这个:使用这些迭代器的实例作为参数来调用std::copy。这不会像发送内容到std::cout那样“解释”输出。虽然C风格的解决方案可能更快。 - user2033018
1
尝试缓冲输出,然后使用大块写入函数(例如 ostream::writefwrite())从缓冲区向文件写入。这应该可以提高性能,无论使用哪种语言。其他微调,如直接写入硬盘,可能没有那么大的影响。 - Thomas Matthews
1
ostream::write() 或 fwrite(),例如。您可以在数据数组上调用每个函数,并告诉它要写入多少字节。对于随机访问,ifstream::seekg() 或 fseek() 将跳转到您想要的任何字节位置,然后像往常一样使用 istream::read() 或 fread()。 - Peter
显示剩余6条评论
4个回答

3

fwritefprintf等函数实际上是在执行write系统调用。与write的唯一区别是这些函数使用缓冲区来减少系统调用的次数。

因此,如果我需要在fwritefprintfwrite之间进行选择,我会避免使用fprintf,因为它是一个功能强大但复杂的函数。如果我真的需要快速处理数据,我会自己重新实现格式化部分,仅保留最基本的要求。在fwritewrite之间,如果我需要写入大量小数据,则会选择fwrite,否则write可能更快,因为它不需要整个缓冲系统。


2
据我所知,最大的瓶颈是逐个字符地写入(例如使用fputc),而不是在内存中构建缓冲区并将整个缓冲区一次性写入(使用fwrite)。经验表明,使用fputc和逐个字符进行写入要慢得多。
这可能是由于硬件因素,而不是某个函数更快。

那么你是在说将更大的数据块发送到文件中更好吗?例如,使用流一次性发送几十个数字/字符串,而不仅仅是一个? - Plasmarob
1
一般来说,编写更大的块是更好的。每次调用输出都会有开销。进行20次调用以每次调用写入1个字符,其开销是进行1次调用以写入20个字符的20倍。 - Thomas Matthews
1
@Plasmarob 是的。我必须加载一个大小为118 Mb的文件。我开始使用fgetc,这需要超过15分钟才能加载完成。我改用fread,时间缩短到了约5分钟。(我知道你谈论的是写入而不是读取。但是相同的思路适用) - Phil_12d3

2

输出性能的瓶颈在于字符格式化。

在嵌入式系统中,我通过将文本格式化为缓冲区(字符数组),然后使用块写命令(如cout.writefwrite)将整个缓冲区发送到输出端来提高性能。这些函数绕过了格式化并几乎直接传递数据。

您可能会遇到操作系统的缓冲。

瓶颈不是由于格式化字符的过程,而是由于多次调用该函数。

如果文本是常量,请勿调用格式化输出函数,而应直接编写:

static const char  Message[] = "Hello there\n";
cout.write(&Message[0], sizeof(Message) - 1);  // -1 because the '\0' doesn't need to be written

1

cout实际上比printf略快,因为它是一个模板函数,所以汇编代码已经针对所使用的类型进行了预编译,尽管速度差异微不足道。我认为你真正的瓶颈不是语言调用,而是硬盘写入速率。如果你真的想走得更远,可以创建一个多线程或网络解决方案,将数据存储在缓冲区中,然后慢慢将数据写入与数据处理分离的硬盘。


1
我认为模板函数由于开销而稍微慢一些。 - Plasmarob
2
它们需要更多的时间来编译,但一旦它们被编译,就只是汇编代码。 - aj.toulan
1
我还会打包您的数据,我的意思是将其序列化或以二进制形式写入文件。因此,不是将“127”写入占用3个字节的文件。我会写入1个字符(char)127,这是一个字节的数据,或者在二进制中为0111 1111。 - aj.toulan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接