Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:cout语句会使代码变慢吗_C++ - Fatal编程技术网

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

C++ C++;:cout语句会使代码变慢吗,c++,C++,我正在从一个文件中读取大约300万行,并将它们插入STL映射。因此,在我的while循环中,我从文件中读取每一行,我还通过一个简单的cout语句打印它是什么行号。我的一个朋友最近指出,这会使代码变慢。我想知道这是不是真的,为什么 几乎可以肯定这是真的。向终端写信以减慢速度而臭名昭著。运行程序并将输出重定向到一个文件,看看它的速度有多快。然后完全取出输出语句并再次测量。你会立即看到这种行为 下面是一个死板的例子: #include <stdio.h> int main(void) {

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

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

下面是一个死板的例子:

#include <stdio.h>

int main(void)
{
    int i;

    for (i = 0; i < 10000; i++)
    {
        printf("Hello, world!\n");
    }
    return 0;
}
重定向I/O的结果:

real 0m0.003s
user 0m0.001s
sys  0m0.001s

好了,快约8倍。这是为一个非常小的打印数量

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

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

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

  • 渲染:
当您写入终端时,这涉及到在屏幕上进行渲染,并且根据终端的不同,可能会涉及其他操作,从而降低程序的速度(并非所有终端都是相同的,您可能会通过切换到不同的终端来发现速度上的显著差异)


如前所述,向终端的写入速度几乎肯定会变慢。为什么?

  • 根据您的操作系统,
    std::cout
    可能会使用行缓冲-这意味着每一行可以分别发送到终端程序。使用
    std::endl
    而不是“\n”时,肯定会刷新缓冲区。以较小的块写入数据意味着额外的系统调用和渲染工作,这会显著降低速度

  • 有些操作系统/编译器甚至更慢,例如,Visual C++:

  • 显示输出的终端需要调用以清除现有屏幕内容、呈现字体、更新滚动条、将行复制到历史记录/缓冲区中。特别是当他们以小片段的形式获得新内容时,他们无法可靠地猜测他们需要等待更多内容的时间,并且可能会尝试更新屏幕以获取他们收到的一点点内容:这很昂贵,而且过度刷新或无缓冲输出速度缓慢也是一个原因

    • 一些终端提供了“跳转滚动”选项,这意味着如果他们发现自己落后了10页,他们会立即呈现最后一页,而之前的9页内容永远不会出现在屏幕上:这可以既好又快。尽管如此,“跳转滚动”并不总是被使用或需要,因为它意味着输出永远不会呈现给最终用户的眼睛:也许在某些情况下,该程序是为了打印一条巨大的红色错误消息-跳转滚动甚至不会有一点闪烁来吸引用户的注意,但如果没有跳转滚动,你可能会注意到它

    • 当我为彭博社工作时,我们有一个持续不断的日志文件更新流,占据了几个监视器——有时显示的输出会落后几分钟;从默认的Solaris xterm切换到rxvt确保它始终保持同步

  • 将输出重定向到/dev/null是一个很好的方法,可以查看您的特定终端有多慢


如果它在做一些额外的事情,那么显然它会变慢。是的,它会使它变慢很多。输出操作很慢。试一下“我的一个朋友最近指出,这会让代码变慢。”-你的好奇心在什么时候没有让你自己去试一下呢?即使我可以凭经验向自己证明,它会让代码变慢并不会改变我对原因的理解。做事情确实需要时间,打印到控制台是你能做的最慢的事情之一。谢谢!这是一个经验证明。但是,到目前为止,还没有人解释原因。为什么写入文件要比打印到控制台快?当重定向到
/dev/null
时,是否也可以进行测试?这将是一个有趣的比较,因为写入文件需要更少的工作。事实上,这可能都是内存中的操作,因为您的操作系统可能有一个文件系统缓存。写入监视器需要与真实硬件交互。为什么不进行优化?如果没有它们,评测(即使是这样一个简单的例子)也是毫无意义的。@GManNickG我认为优化程序并不能提高终端的渲染时间。或者像缓冲这样的东西可以优化吗?我不这么认为,但我可能是错的。“向终端写入默认使用行缓冲”-你能用一些证据证明这一点吗?据我所知,
cout
通常默认为完全缓冲,
cerr
行缓冲。尽管如此,有些人还是有一个可怕的习惯,不必要地使用
std::endl
,这会刷新流。使用
\n
通常更合适。@TonyD:这在中讨论过。该标准只规定,当连接到终端时,
cout
可能没有完全缓冲,但在Unix和Windows上它是行缓冲的。这是C99的问题。我刚刚检查了C++11标准中提到的每一个cout,根本没有重新缓冲的要求(除了与
cin
的联系)。它说的是27.4.2.3“对象cout控制与对象stdout关联的流缓冲区的输出,在(27.9.2)中声明。”。但是-至少对于UNIX,当指向t时,标准输出是行缓冲的
real 0m0.003s
user 0m0.001s
sys  0m0.001s