【问题标题】:Why is ostringstream faster than ofstream为什么ostringstream比ofstream快
【发布时间】:2011-07-08 17:07:07
【问题描述】:

要将多条数据写入文件,我有两种方法:

  1. 直接一一写入ofstream

    ofstream file("c:\\test.txt");
    for (int i = 0; i < 10000; ++i)
    {
        file << data[i];
    }
    
  2. 先写入istringstream,再写入ofstream

    ostringstream strstream;
    for (int i = 0; i < 10000; ++i)
    {
        strstream << data[i];
    }
    ofstream file("c:\\test.txt");
    file << strstream.str();
    

毫不奇怪,第二种方法更快,事实上,在我的 HP7800 机器上它比第一种方法快 4 倍。

但是为什么呢?我知道 ofstream 在内部使用 filebuf,而 ostringstream 正在使用 stringbuf - 作为缓冲区,它们都应该驻留在内存中,因此应该没有区别。

引擎盖下有什么区别?

【问题讨论】:

    标签: c++ filestream iostream


    【解决方案1】:

    您是否经常使用std::endl 而不是'\n'std::endl 做了两件事:它将'\n' 插入到流中,然后将缓冲区刷新到磁盘。我已经看到代码说这样做会严重影响性能。 (修复后代码运行速度提高了 5-10 倍。)
    刷新到字符串缓冲区将比刷新到磁盘快得多,因此这可以解释您的发现。

    如果不是这种情况,您可能会考虑增加缓冲区大小:

    const std::size_t buf_size = 32768;
    char my_buffer[buf_size];
    ofstream file("c:\\test.txt");
    file.rdbuf()->pubsetbuf(my_buffer, buf_size);
    
    for (int i = 0; i < 10000; ++i)
    {
        file << data[i];
    }
    

    【讨论】:

    • 谢谢,这是由于附加 std::endl 频繁刷新造成的。事实证明,filebuf 和 stringbuf 都可以在内存缓冲区不够的时候增加它的内存缓冲区大小。见here
    • 现在我在想为什么它为我们提供了一个 pubsetbuf 来设置缓冲区, - 也许当我们已经在内存中有一些内容时使用它,而不是附加它到 streambuf - 我们只是让 streambuf 指向它。
    • @lzprgmr: 1) 所以我的第一个假设是正确的。好的。 2) 流缓冲区通常不会增长它们的缓冲区,而是在溢出时刷新到设备。字符串流缓冲区是一个例外,因为它的“设备”是一个内存缓冲区(您可以从中获取字符串)。 3)pubsetbuf()可以在您了解更多环境/设备时使用。然后,您可以为流提供您认为合适的任何大小的缓冲区。我不确定除了提供 custom-sized 缓冲区是否还有用例。
    • 我做了一个测试,如果缓冲区的大小不够,filebuf 将被强制刷新 - 不要像 stringbuf 那样继续增长。
    • 哇,从切换 endl 到 "\n" 的速度大幅提升,谢谢!
    【解决方案2】:

    磁盘很慢。许多小写比一个大写更昂贵。

    【讨论】:

    • 但这应该通过缓冲来避免。
    • ofstream 不会无限期缓冲,只要内部缓冲区达到阈值就会写入。
    • 你知道阈值是多少吗?有没有参考。从this api 的描述来看,好像内存不够会增加内存。
    • @lzprgmr:抱歉,不知道,我相信这取决于实现。 sbi 的回答显示了如何更改它。
    【解决方案3】:

    这可能是特定操作系统的实施问题。 另外我猜ofstream缓冲区(buflen)小于10000,典型值为4095。所以尝试使用i

    第二种情况更快的原因:

    在第一种情况下,当缓冲区已满 (buflen=4095bytes) 时,它会被写入磁盘。所以对于 i

    在第二种情况下,所有数据首先在 RAM 中准备好,然后一次性刷新到硬盘。所以已经保存了两次刷新!

    【讨论】:

      猜你喜欢
      • 2010-10-01
      • 2020-01-20
      • 2018-08-06
      • 2019-11-02
      • 1970-01-01
      • 2015-07-24
      相关资源
      最近更新 更多