我正在从一个文件中读取大约 300 万行并将它们插入到 STL 映射中。因此,在我从文件中读取每一行的 while 循环中,我还通过一个简单的 cout 语句打印以控制台它是什么行号。我的一位朋友最近指出,这会使代码变慢。我想知道这是不是真的,如果是为什么?
3 回答
如前所述,写入终端几乎肯定会变慢。为什么?
- 缓冲:
写入终端line buffering
默认使用 *。这意味着每次遇到换行符时都会传输缓冲区的内容。写入文件时,仅当缓冲区已满或手动刷新流时才会刷新缓冲区。这是造成差异的主要原因,因为 I/O 操作的数量显着不同。
*:这对于 Unix 实现是正确的,但其他实现可能是无缓冲的(参见评论中的讨论)。
- 渲染:
当您写入终端时,这涉及在屏幕上呈现,并且取决于终端可能涉及可能减慢程序速度的其他操作(并非所有终端都相同,您可能会通过切换到不同的)。
如前所述,写入终端几乎肯定会变慢。为什么?
根据您的操作系统,
std::cout
可能会使用行缓冲 - 这意味着每行可以单独发送到终端程序。当您使用std::endl
而不是 '\n' 时,它肯定会刷新缓冲区。以较小的块写入数据意味着额外的系统调用和渲染工作会显着减慢速度。一些操作系统/编译器甚至更慢 - 例如,Visual C++:https ://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance -c 库中的错误
显示输出的终端需要调用以清除现有屏幕内容、渲染字体、更新滚动条、将行复制到历史记录/缓冲区中。尤其是当他们获得小块的新内容时,他们无法可靠地猜测他们需要等待多长时间,并且可能会尝试更新他们收到的一小部分内容:这是昂贵的,而且过度刷新或无缓冲输出缓慢的原因。
一些终端提供“跳转滚动”选项,这意味着如果他们发现他们说落后 10 页,他们会立即呈现最后一页,而前 9 页的内容永远不会出现在屏幕上:这既好又快。尽管如此,“跳转滚动”并不总是被使用或想要,因为它意味着输出永远不会呈现给最终用户的眼睛:也许程序在某些情况下会打印一个巨大的红色错误消息 - 跳转滚动甚至不会闪烁一下就可以引起用户的注意,但是如果没有跳转滚动,您可能会注意到它。
当我在彭博工作时,我们有一个持续不断的日志文件更新流,占用了几个监视器——有时显示的输出会落后几分钟;从默认的 Solaris xterm 切换到 rxvt 确保它始终保持同步
redirecting output to /dev/null is a good way to see how much your particular terminal is slowing things down
这几乎可以肯定是真的。向终端写入以减慢速度而臭名昭著。运行你的程序并将输出重定向到一个文件,看看它有多快。然后将输出语句全部取出,再次测量。您将立即看到该行为。
这是一个脑残的例子:
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 10000; i++)
{
printf("Hello, world!\n");
}
return 0;
}
我构建了这个未优化的程序并运行它,一次输出到终端,一次输出到文件。终端输出的结果:
real 0m0.026s
user 0m0.003s
sys 0m0.007s
重定向 I/O 的结果:
real 0m0.003s
user 0m0.001s
sys 0m0.001s
就这样,速度快了约 8 倍。那是为了极少数的印刷品!