C++:cout语句会使代码变慢

Zan*_*nam 6 c++

我正在从文件中读取大约300万行并将它们插入到STL映射中.所以,在我的while循环中,我从文件中读取每一行,我还打印到通过一个简单的cout语句控制它是什么行号.我的一位朋友最近指出,这会使代码变慢.我想知道这是否属实,是不是为什么?

Jes*_*ood 6

如前所述,写入终端几乎肯定会变慢.为什么?

  • 缓冲:

写入终端line buffering默认使用*.这意味着每次遇到换行时都会传输缓冲区的内容.写入文件时,仅在缓冲区已满或手动刷新流时才刷新缓冲区.这是造成差异的主要原因,因为I/O操作的数量明显不同.

*:这适用于Unix实现,但其他实现可能是无缓冲的(请参阅注释中的讨论).

  • 渲染:

当您写入终端时,这涉及在屏幕上呈现,并且取决于终端可能涉及其他可能降低程序速度的操作(并非所有终端都相同,您可能会发现只需切换到不同的).


Ton*_*roy 6

如前所述,写入终端几乎肯定会变慢.为什么?

  • 根据您的操作系统,std::cout可以使用线路缓冲 - 这意味着每条线路可以分别发送到终端程序.当你使用std::endl而不是'\n'时,它肯定会刷新缓冲区.以较小的块编写数据意味着额外的系统调用和渲染工作会显着减慢速度.

  • 某些操作系统/编译器甚至更慢 - 例如,Visual C++:https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance -bug式-C库

  • 显示输出的终端需要拨打电话以清除现有的屏幕内容,渲染字体,更新滚动条,将线条复制到历史/缓冲区.特别是当他们以小块形式获得新内容时,他们无法可靠地猜测他们需要多长时间等待更多内容并且可能会尝试更新屏幕以获得他们收到的一点点:这是昂贵的,并且过度冲洗或无缓冲输出的原因很慢.

    • 有些终端提供"跳转滚动"选项,这意味着如果他们发现他们说10页后面会立即呈现最后一页,而前9页的内容永远不会出现在屏幕上:这可能很好而且快速.仍然,"跳跃滚动"并不总是被使用或想要,因为它意味着输出永远不会呈现给最终用户的眼睛:也许该程序在某些情况下打印出一个巨大的红色错误消息 - 跳跃滚动甚至不会它是一个闪烁的引起用户的注意,但没有跳转滚动你可能会注意到它.

    • 当我在Bloomberg工作时,我们有一个恒定的日志文件更新流占用几个监视器 - 有时显示的输出会落后几分钟; 从默认的Solaris xterm切换到rxvt确保它始终保持同步

  • 将输出重定向到/ dev/null是查看特定终端减慢速度的好方法


Car*_*rum 5

这几乎可以肯定是真的。写入终端因拖慢速​​度而臭名昭著。运行你的程序并将输出重定向到一个文件,看看它的速度有多快。然后将输出语句完全取出并再次测量。你会立即看到行为。

这是一个脑残的例子:

#include <stdio.h>

int main(void)
{
    int i;

    for (i = 0; i < 10000; i++)
    {
        printf("Hello, world!\n");
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我构建了这个未优化的程序并运行它,一次输出到终端,一次输出到文件。终端输出的结果:

real 0m0.026s
user 0m0.003s
sys  0m0.007s
Run Code Online (Sandbox Code Playgroud)

重定向 I/O 的结果:

real 0m0.003s
user 0m0.001s
sys  0m0.001s
Run Code Online (Sandbox Code Playgroud)

好了,快了 8 倍。这适用于非常少量的印刷品!

  • 为什么没有优化?如果没有它们,分析(即使是像这样的简单示例)也毫无意义。 (2认同)
  • @GManNickG 我不认为优化*程序* 会改善*终端的渲染时间*。或者可以优化缓冲之类的东西吗?我不这么认为,但我可能是错的。 (2认同)