1

更新

@Ruslan 指出为什么 snprintf 在打印单个数字时始终比 ostringstream 快 2 倍?它提供了错误报告的答案和链接。

原始问题

我的总体感觉表明,使用 C++ofstream<<运算符应该具有相似的性能,前提是我使用endl但字面量"\n"来跳过隐式刷新。

另外,这个问题支持了我的想法。

因此,在下面的示例中,我希望运行时大致相似,但在流媒体方面略有优势。

#include <cstdio>
#include <string>
#include <fstream>

#include <boost/timer/timer.hpp>

using namespace std;

const int LOOPS = 10000000;
const double d = 1.231;
const float f = 1.232;
const char *s = "1.233";

void stream_out() {
    boost::timer::auto_cpu_timer t;

    ofstream out;
    out.open("ofstream");
    for(int i = 0; i < LOOPS; ++i) {
        out << d << "\n";
        out << f << "\n";
        out << s << "\n";
    }
}

void print_out() {
    boost::timer::auto_cpu_timer t;

    FILE* fout = fopen("fprintf", "w");
    for(int i = 0; i < LOOPS; ++i) {
        fprintf(fout, "%g\n", d);
        fprintf(fout, "%g\n", f);
        fprintf(fout, "%s\n", s);
    }
}

int main() {
    stream_out();
    print_out();
    return 0;
}

然而,情况似乎并非如此。当使用 g++ 构建并在我的 RHEL7 机器上运行时,这显示:

$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -O2 -o test test.cpp -lboost_timer -lboost_system

$ ./test
 7.697337s wall, 6.660000s user + 0.160000s system = 6.820000s CPU (88.6%)
 4.724694s wall, 4.580000s user + 0.130000s system = 4.710000s CPU (99.7%)

那么,我在这里的误解是什么?不应该ofstream稍微快一点,因为它不需要在运行时解析格式字符串和可变参数 args?我错过了一些明显的东西吗?

fprintf()仅仅恢复到这样的性能差异将是一种耻辱。

4

1 回答 1

2

编辑:正如评论,我的原始答案仅适用于标准输出和 cout,不适用于文件。我这边的一些测试似乎表明 cout 的默认 double 到 string 转换是罪魁祸首。

file << std::to_string(d) << '\n';

好像已经把差价减半了。

原答案:

标准 C 流和标准 C++ 流是两个不同的系统。默认情况下,这两者正在同步以便能够混合使用 printf 和 cout,本质上是 iostream 调用的复制加倍。

这将禁用额外的同步,并应减少速度差异:

std::ios::sync_with_stdio(false);

https://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio

于 2019-09-19T16:34:22.890 回答