我试图了解输出流缓冲区的工作方式。我没有发现任何可以解释在std::cout
上下文中对标准输出进行编写的整个过程的信息。据我了解,std::cout
实际上并没有在标准输出上打印,而是将内容写入终端仿真器的输出流缓冲区。当缓冲区已满时,终端仿真器将删除缓冲区的内容,并将其写入终端显示(标准输出)。据我说,这是由终端仿真器执行flush
操作时发生的情况。
在std::endl
的情况下,向终端仿真器提出了显式请求,以立即刷新缓冲区的内容,这会导致性能下降。造成此下降的原因是我们的程序花费了很长时间才能向终端仿真器创建flush
请求,并等待缓冲区的内容在终端显示器上打印,然后再继续执行下一行代码。如果没有std::endl
,std::cout
不会关心立即打印内容。它将打印责任留给终端仿真器(通过将内容写入终端仿真器的输出流缓冲区中)。我有一些疑问:
(1)我对终端模拟器如何显示std::cout
请求的文本是否准确?
(2)是否向操作系统或终端仿真器发出了flush
请求?
(3)如果我们增加了终端仿真器的输出流缓冲区的大小,那么程序的性能是否会得到提高,并在显示屏上打印内容时出现明显的延迟?
答案 0 :(得分:2)
不,您的理解不正确。至少不直接涉及“终端仿真器”。
输出缓冲区位于流对象本身内(在这种情况下为std::cout
)。根据流的缓冲策略,可以使用三种方法使用此缓冲区:
块缓冲:输出首先存储在缓冲区中。当缓冲区已满时,它将“清除”,即,其内容将写入底层(特定于OS的)输出通道,并清空缓冲区。
行缓冲:类似于块缓冲,但是每当将换行符('\n'
)写入缓冲区时,缓冲区也会被刷新。
未缓冲:不使用输出缓冲区。所有输出将立即写入。
打开文件时,流开始被块缓冲。 std::cerr
是无缓冲的。如果输出到终端,std::cout
将被行缓冲,否则将被块缓冲。
std::flush
立即刷新输出缓冲区(如果有的话)。
关于数据的实际写入方式,详细信息取决于您的操作系统。在UNIX系统上,有一个名为write
的系统调用(“系统调用”是对操作系统的要求。)系统调用通常比普通函数调用慢。输出缓冲区是一种性能优化,因为您不想为输出的每个字符调用write
。内部收集输出,直到您要编写大量文本为止,这意味着对write
的调用减少,这意味着更好的总体性能。
关于您的具体问题:
不,终端仿真器不相关。
操作系统。
缓冲区位于流对象中,而不是终端仿真器中。在某些时候,增加缓冲区大小将停止为您提供任何性能优势。您的程序通常会花费大部分时间来计算结果和执行其他操作,而不是将文本写入std::cout
。