【问题标题】:printf more than 5 times faster than std::cout?printf 比 std::cout 快 5 倍以上?
【发布时间】:2012-08-16 04:17:09
【问题描述】:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>

int main(int argc, char* argv[])
{
    std::clock_t start;
    double duration;    

    std::cout << "Starting std::cout test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
    {
        std::cout << "Hello, World! (" << i << ")" << std::endl;
    }

    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Ending std::cout test." << std::endl;
    std::cout << "Time taken: " << duration << std::endl;

    std::system("pause");

    std::cout << "Starting std::printf test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
    {
        std::printf("Hello, World! (%i)\n", i);
        std::fflush(stdout);
    }

    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Ending std::printf test." << std::endl;
    std::cout << "Time taken: " << duration << std::endl;

    system("pause");

    return 0;
}

现在,这是前五次运行的时间:

  • std::cout 测试:1.125 s ; printf 测试:0.195
  • std::cout 测试:1.154 s ; printf 测试:0.230
  • std::cout 测试:1.142 s ; printf 测试:0.216
  • std::cout 测试:1.322 s ; printf 测试:0.221
  • std::cout 测试:1.108 s ; printf 测试:0.232

如您所见,使用printf,然后使用fflushing 所用时间比使用std::cout 少约5 倍。

虽然我确实预计使用std::cout&lt;&lt; 运算符可能会慢一些(几乎是最小的),但我并没有为这种巨大的差异做好准备。我在做一个公平的测试吗?如果是这样,那么是什么让第一个测试比第二个测试慢得多,如果它们本质上做的是完全相同的事情?

【问题讨论】:

  • 他也确实在 printf 版本中刷新过,所以不可能吗?
  • possible duplicate 问题没有回答我的主要问题,**what makes** the first test so much slower than the second one...为什么 printf 究竟更快?
  • 除了您使用的库实现的质量之外,可能没有一个正确的答案。 this linked one等类似的问题已经出现过。阅读它以及它链接到的相关问题。
  • 注意std::cout &lt;&lt; "Hello, World! (" &lt;&lt; i &lt;&lt; ")" &lt;&lt; std::endl;是4个函数调用,而printf只有一个。尝试做printf 5 次,就像cout 一样,看看会发生什么。然后你会意识到有多少性能失败是由于函数调用,还有多少是由于库本身。
  • 您当前的时间是没有意义的,因为 std::cout 与 stdout 同步,因此需要做很多“额外”的工作来保持同步。如果你解耦它们,你会看到加速(它仍然更慢)std::cout.sync_with_stdio(false);

标签: c++ performance printf cout


【解决方案1】:

试试这个:

#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <iostream>

int main(int argc, char* argv[])
{
#if defined(NOSYNC)
    std::cout.sync_with_stdio(false);
#endif

    std::cout << "Starting std::cout test." << std::endl;

    std::clock_t start = std::clock();

    for (int i = 0; i < 1000; i++)
    {   
        std::cout << "Hello, World! (" << i << ")" << std::endl;
    }   

    clock_t mid = std::clock();

    for (int i = 0; i < 1000; i++)
    {   
        std::printf("Hello, World! (%i)\n", i); 
        std::fflush(stdout);
    }   

    std::clock_t end = std::clock();

    std::cout << "Time taken: P1 " << ((mid-start)*1.0/CLOCKS_PER_SEC) << std::endl;

    std::cout << "Time taken: P2 " << ((end-mid)*1.0/CLOCKS_PER_SEC) << std::endl;


    return 0;
}

然后我得到:

> g++ -O3 t13.cpp
> ./a.out
# lots of lines deleted
Time taken: P1 0.002517
Time taken: P2 0.001872

> g++ -O3 t13.cpp -DNOSYNC   
> ./a.out
# lots of lines deleted
Time taken: P1 0.002398
Time taken: P2 0.001878

所以 P2 时间不会改变。
但是使用std::cout.sync_with_stdio(false); 可以提高P1 时间(即std::cout)。因为代码不再尝试保持两个流 (std::cout stdout) 同步。如果您正在编写纯 C++ 并且仅使用 std::cout 则不是问题。

【讨论】:

    【解决方案2】:

    要进行真正的同类比较,请重新编写测试,以便在测试用例之间唯一改变的是正在使用的打印函数:

    int main(int argc, char* argv[])
    {
        const char* teststring = "Test output string\n";
        std::clock_t start;
        double duration;
    
        std::cout << "Starting std::cout test." << std::endl;
        start = std::clock();
    
        for (int i = 0; i < 1000; i++)
            std::cout << teststring;
        /* Display timing results, code trimmed for brevity */
    
        for (int i = 0; i < 1000; i++) {
            std::printf(teststring);
            std::fflush(stdout);
        }
        /* Display timing results, code trimmed for brevity */
        return 0;
    }
    

    这样,您将只测试printfcout 函数调用之间的差异。你不会因为多次&lt;&lt; 调用等而产生任何差异。如果你尝试这个,我怀疑你会得到一个非常不同的结果。

    【讨论】:

    • 嗯,现在只差0.06秒左右。猜猜这回答了我的问题。
    • @bta,这似乎是一个不公平的测试。对于 printf 部分,您在每次迭代后刷新标准输出,但 std::cout 代码不是。应该可能添加
    • 添加以下内容:std::cout.sync_with_stdio(false);
    • 如果 cout 和 printf 之间的性能差异是由于将数字 i 格式化为字符串造成的,那么这不是一个有用的比较。
    • 如果差异是由于需要更多的&lt;&lt; 调用而不是printf 调用,那么以这种方式比较它们是完全合适的。将测试简化到您所拥有的程度是不现实的。
    【解决方案3】:

    使用

    cout << "\n";
    

    防止缓冲。更快

    【讨论】:

      【解决方案4】:

      大约 10 年前,Scott Meyers 测试了 iostreamscanf/printf 的效率。取决于编译器和环境,有时 scanf/printf 比 iostream 快 20%,有时甚至快 200%。但是 iostream 从来没有比 scanf/printf 快。根据其他两个给定的示例,scanf/printf 仍然比 iostream 快。 然而,迈耶斯说:“在一个真正有用的程序上,不会有任何差异。” 根据 Google 的编程风格([http://google-styleguide.googlecode.com/svn/trunk/cppguide.html]),除了日志记录之外,不应使用流。 iostream 的替代方法是自己封装 scanf/printf。

      【讨论】:

        【解决方案5】:

        我只有一台电脑的编程范围,所以没有太多的测试。无论如何,std::cout 在我的构建中使用精确的详细代码更快。我正在使用 Cpp14。

        我只是认为某些人会选择 C++。是的,C 是很棒的语言,但从逻辑上讲,我看不出 printf 如何比 std cout 更快。 Printf 必须在运行时从 void 指针进行类型转换。 Cout 在编译时执行此操作。

        【讨论】:

        • 如果 iostreams 在您的平台上实际上更快,那么了解该平台是什么会很有用。 iostreams 往往比 printf 慢很多的原因是 iostreams 使用了大量的函数调用,包括大量的虚函数调用(iostream 本身不做任何事情,它转发streambuf 虚函数的所有内容)。如果您需要重定向流,这非常有用,但如果您不使用它,则很浪费。
        • 好吧,我真的不知道你指的是什么平台,但我使用的是 Win 10、Intel Celeron CPU G3900、4 gigs Ram、CPP 14。你应该记住 CPP 每三年发展一次。很多函数调用都被编译掉了。
        • 哪个编译器和哪个 C++ 标准库是平台的非常重要的细节...... CPU(你提到的,还包含缓存信息)和 RAM(你只提到了大小而不是时钟速率、DDR 生成、通道数或延迟)在这种情况下不太重要,但有时会对性能和优化产生很大影响。
        【解决方案6】:

        我在运行 Windows 10、WSL Ubuntu、CLion 2018、GCC 的笔记本电脑上尝试了这个测试。没有优化:

        #include <iostream>
        #include <cstdlib>
        #include <cstdio>
        #include <ctime>
        
        int main(int argc, char *argv[]) {
            std::ios_base::sync_with_stdio(false);
            std::cin.tie(nullptr);
            std::clock_t start;
            double duration1, duration2;
        
            std::cout << "Starting std::cout test.\n";
            start = std::clock();
        
            for (int i = 0; i < 100000; i++) {
                std::cout << "Hello, World! (" << i << ")" << std::endl;
            }
        
            duration1 = (std::clock() - start) / (double) CLOCKS_PER_SEC;
        
            std::cout << "Starting std::printf test.\n";
            start = std::clock();
        
            for (int i = 0; i < 100000; i++) {
                std::printf("Hello, World! (%i)\n", i);
                std::fflush(stdout);
            }
        
            duration2 = (std::clock() - start) / (double) CLOCKS_PER_SEC;
        
            std::cout << "Time taken: cout " << duration1 << std::endl;
            std::cout << "Time taken Printf: " << duration2 << std::endl;
        
            return 0;
        }
        

        结果:

        Test1: Cout: 2.25, Printf: 2.45312  (Cout run first)
        Test2: Cout: 2.42188, Printf: 2.07812 (Printf Run first)
        Test3: Cout: 2.26562, Printf: 2.25 (Cout run first)
        Test4: Cout 2.46875, Printf: 2.57812 (Printf run first)
        

        TL;DR:使用 std::ios_base::sync_with_stdio(false)std::cin.tie(nullptr) 可以将这两个功能带到几乎相同的位置。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-19
          • 1970-01-01
          • 2017-01-11
          • 2016-12-29
          • 2014-12-06
          • 1970-01-01
          • 2017-06-02
          • 1970-01-01
          相关资源
          最近更新 更多