std::ifstream比FILE慢很多吗?

15
我被告知我的库比应该慢了30倍以上,解析一个特定的文件(文本文件,大小为326 kb)太慢了。用户建议可能是我使用了std::ifstream(可能是代替FILE)。
我不想盲目重写,所以我想先在这里检查一下,因为我猜测瓶颈可能在其他地方。我正在逐个字符地读取,所以我只使用了get()peek()tellg()/seekg()这几个函数。
更新:
我进行了分析,并得到了confusing输出 - gprof似乎没有认为它需要那么长时间。我将程序重写为首先将整个文件读入缓冲区,速度提高了约100倍。我认为问题可能是tellg()/seekg()花费了很长时间,但出于某种原因,gprof可能无法看到这一点。无论如何,即使对于这个大小,ifstream也不会缓冲整个文件。

长命 gprof,作为博物馆藏品。 - Mike Dunlavey
6个回答

29

我认为这不会有任何区别,特别是如果你按字符读取,I/O的开销可能会完全支配任何其他操作。 为什么要逐个字节地阅读? 你知道这是多么低效吗?

对于326kb的文件,最快的解决方案很可能是一次性将其全部读入内存。

std :: ifstream和C语言中等效方法之间的区别基本上只是一个或两个虚函数调用。如果每秒执行数千万次,则可能会产生影响,否则实际上不会。 文件I/O通常非常缓慢,因此用于访问它的API并不真正重要。 更重要的是读/写模式。 大量搜索是不好的,顺序读/写是好的。


1
其实,我不知道它有多低效。我只是假设在幕后,它会将其读入内存。我想我会这样做。 - Jesse Beder
4
部分输入流是带有缓冲的。如果你的代码一次只读取一个字符,这并不意味着底层的流也是这样做的。 - jfs
5
FILE和fstream都是有缓冲区的(尽管缓冲区可能太小了),Linux会对磁盘访问进行优化,因此相对较小的文件会被加载到内存中(Windows也是如此)。 - Ismael
2
取决于缓冲区的大小等因素。我愿意打赌一口气读完整个文件仍然会更快。 - jalf
@jalf:这是一个容易说的话。它可能会更快,但我愿意打赌不会有显著的差别。 - Martin York
我有一种感觉他是按字符的读取->处理->写入模式。所有缓冲策略都将失效。 - jpinto3912

4

它应该会稍微慢一些,但正如你所说,它可能不是瓶颈。为什么不对你的程序进行分析,看看情况是否如此?


3

所有的基准测试都是有问题的。只需要为你预计的数据对代码进行分析。

我曾经在Ruby、Python、Perl和C++之间进行了一次I/O性能比较。针对我的数据、语言版本等因素,C++的变体比其他语言慢了几倍(那时候这个结果让我非常惊讶)。


C语言怎么样?如果除了C++之外的任何一种语言都比C运行得更快,我会非常惊讶。 - rr-
@rr- 如果你的硬盘无法提供高于100M/s的数据传输速度,那么你的C程序每秒处理1G的速度也没有意义。正如其他答案已经指出的那样,磁盘I/O通常比程序中的任何其他操作都要慢得多。请参阅有关I/O性能的相关问题:为什么在C++中从stdin读取行比Python慢得多?在C++中一次性读入整个文件,第2部分 - jfs
在你的帖子中,你说C++在Ruby、Python和其他语言中表现最差。这与I/O性能无关,因为这对所有这些语言来说都是一个瓶颈。而且这就是我会感到惊讶的地方,因为比如说Ruby是用C写的,所以我很难相信C的表现会比Ruby更差。 - rr-
@rr-: 1. 如果 I/O 占主导地位,则语言并不重要,除非你是 Google。2. 如果文件已缓存,则请阅读我提供的链接,了解使用相同语言编写的程序可能会为同一问题显示不同的性能结果。 - jfs

3
我认为,通过从fstream转换为FILE*来解决问题的可能性不大,因为它们通常都由C库进行缓存。此外,操作系统可以缓存读取(在这方面,Linux非常出色)。考虑到您正在访问的文件的大小,很可能它已经完全存在于RAM中。
像PolyThinker所说,您最好通过分析器运行程序并确定问题所在。
此外,您正在使用seekg / tellg,如果您的磁盘严重碎片化,这可能会导致明显的延迟,因为要首次读取文件时,磁盘必须将磁头移动到正确的位置。

2

我同意你需要进行性能分析。但如果您正在逐个字符地读取文件,为什么不创建一个内存映射文件呢?这样,您可以将文件视为字符数组,操作系统应该会为您处理所有低级缓冲区。在我的书中,最简单且可能最快的解决方案是胜利者 :)


2
这里有一个优秀的基准测试(链接),它表明在极端情况下,fstream实际上相当慢...除非:
  1. 使用缓冲区(我不能强调这一点)
  2. 自己操作缓冲区(也就是说,如果你需要像链接问题中的OP那样的性能),这与使用FILE*并没有太大区别。
虽然你不应该过早地进行优化,但fstreams通常更好,如果你需要在以后将它们优化下来,你可以随时以很少的代价来完成。为了提前做最坏的打算,我建议现在创建一个最小的fstream代理,以便以后可以优化它,而无需触及其他任何东西。

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