有人可以更明确地解释缓冲区的概念吗?我知道缓冲区是存储字符的数据结构,以及从中读取数据的位置.冲洗缓冲区的想法是什么?
刷新缓冲区时,这是指写入存储在其中的字符的行为吗?
从文字:
To avoid the overhead of writing in response to each output request, the library uses the
buffer to accumulate the characters to be written, and flushes the buffer, by writing its
contents to the output device, only when necessary. By doing so, it can combine several
output operations into a single write.
Run Code Online (Sandbox Code Playgroud)
当提到"刷新"时,几乎使其听起来好像缓冲区正在写入但同时也被擦除.只是猜测.
那么,为了写入屏幕上的视图需要缓冲区刷新?
When our program writes its prompt to cout, that output goes into the buffer associated
with the standard output stream. Next, we attempt to read from cin. This read flushes
the cout buffer, so we are assured that our user will see the prompt.
Run Code Online (Sandbox Code Playgroud)
在这里,听起来好像通过在结尾处使用'endl'它告诉系统它需要立即写入(暗示否则不会?)什么是endl未使用?
Writing the value of std::endl ends the line of
output, and then flushes the buffer, which forces the system to write to the output
stream immediately.
Run Code Online (Sandbox Code Playgroud)
Die*_*ühl 24
缓冲的基本思想是将操作组合成更大的块:不是读取少量字节,而是读取整个页面并按要求使其可用; 而不是写入少量字节,缓冲它们并写入整个页面或明确请求写入时.从本质上讲,这是一项重要的性能优化.对于I/O操作来说非常明确,但通常也适用于其他用途:一次处理多个单元通常最终比处理单个单元更快.
关于I/O 刷新是指将当前缓冲的字节写入其目的地 - 无论这在实践中意味着什么.对于C++,IOStreams刷新流量相当于调用成员函数std::ostream::flush(),而成员函数又调用std::streambuf::pubsync()相关的流缓冲区(这忽略了流实际上是类模板的细节,例如std::basic_ostream<cT, traits>;出于讨论的目的,它们并不重要. class templates):基类std::streambuf是C++关于如何处理某个流的抽象.它在概念上分别由输入和输出缓冲器以及负责读取或写入缓冲器的虚函数组成.该函数std::streambuf::pubsync()调用虚函数std::streambuf::sync(),该函数应该为每个可能缓冲字符的流缓冲区重写.也就是说,刷新实际意味着什么取决于虚拟功能的实现方式.
是否覆盖sync()实际上做了什么以及它做了什么显然取决于流缓冲区代表什么.例如,对于std::filebuf负责读取或写入文件的负责,sync()写入缓冲区的当前内容并从缓冲区中删除刷新的字符.鉴于文件可能并不真正代表物理文件,而是例如与不同进程通信的命名管道,这是合理的行为.另一方面,刷新一个std::stringbuf用于实现写入的流缓冲区,std::string例如std::ostringstream实际上没有做任何事情:字符串完全在程序中,并且在调用成员函数std::string时构造表示其值std::stringbuf::str().对于用户定义的流缓冲区,有许多不同的行为.一个常见的流缓冲区类是在将输出传递给另一个流缓冲区之前以某种方式过滤输出(例如,日志缓冲区可能在每个换行符后添加时间戳).这些通常只调用std::streambuf::pubsync()下一个流缓冲区的功能.
因此,对实际行为的描述通常保持相当模糊,因为不清楚究竟发生了什么.从概念上讲,刷新流或调用pubsync()流缓冲区应该更新字符的外部目标以匹配当前的内部状态.通常,这相当于转发当前缓冲的字符并将其从内部缓冲区中删除.在这一点上值得注意的是,缓冲区通常也会在它刚刚满时写入.当它变满时再次依赖于特定的流缓冲区.一个好的实现std::filebuf将基本上填充匹配底层页面大小(或其倍数)的字节缓冲区,然后编写完整的页面,最小化所需的I/O操作的数量(这实际上是相对棘手的,因为缓冲区大小在不同的文件系统之间是不同的,并且取决于在写入所产生的字节数时所使用的编码不能容易地估计).
标准C++库通常不需要显式刷新:
std::cerr被设置为自动刷新在调用每个输出操作之后产生的任何输出.这是std::ios_base::unitbuf默认设置格式化标志的结果.要关闭此功能,您可以使用std::cerr << std::nounitbuf或者您只能使用std::clog哪个写入到同一目的地但不执行此刷新.std::istream"捆绑"中读取时std::ostream,如果有,则刷新.默认情况下std::cout绑定std::cin.如果你想设置一个绑std::ostream自己,你可以使用eg in.tie(&out)或,如果你想删除绑,std::ostream你可以使用例如std::cin.tie(0).std::ostream被破坏时(或者当它std::ostream是标准流之一时它通常会被破坏),它std::ostream被刷新.std::streambuf::overflow()调用虚函数,该函数通常将当前缓冲区的缓冲区(加上传递的字符,如果有的话)写入其目标.这通常只需要调用sync()清除当前缓冲区来完成,但再次完成的操作取决于具体的流缓冲区.您还可以明确请求刷新std::ostream:
std::ostream::flush(),例如std::cout.flush().std::streambuf::pubsync(),例如std::cout.rdbuf()->pubsync()(假设有一个流缓冲区设置; std::ostream::flush()如果没有流缓冲区,则调用将不执行任何操作).std::flush,例如std::cout << std::flush.std::endl,例如std::cout << std::endl首先编写换行符然后刷新流.请注意,std::endl 只有在真正意味着刷新输出时才应该使用.当你真正想要创建一个行尾时不要使用std::endl!只为后者写一个换行符!在任何情况下,如果你只写了几个字符不会引起流缓冲区缓存溢出,什么都不会与他们直到他们是隐式或显式刷新发生.通常,这不是一个问题,因为其中的缓冲输出正常情况下需要从读取时成为可用的,即std::cin,通过处理std::cout正在tie()d到std::cin.当使用其他I/O机制时,可能需要明确tie()相关的流.如果程序在调试期间"崩溃"或断言,缓冲区有时会出现问题,因为某些流输出可能已经发出但尚未发送.对此的补救措施是使用std::unitbuf.
想象一下,如果每次您将一个字节“写入”磁盘文件时,您的程序实际上会写入磁盘,读入当前扇区/簇/块,更改单个字节,然后将其写回物理磁盘,会发生什么情况?磁盘。
我想说,就性能而言,您的软件最好被描述为“冰川”:-)
缓冲是一种批量读取和写入以提高效率的方法。
例如,如果您正在写入磁盘文件,它可能会等到您拥有完整的 4K 块后再将其写入磁盘。
读取时,即使您只请求十个字节,它也可能会得到一个 4K 块,假设您可能很快就会请求其余的字节。
一旦缓存已满,写入刷新就会隐式发生,或者根据请求显式发生(通过刷新调用或关闭文件)。
请注意,此文件缓冲只是缓冲的一种,该概念可以用在任何可以通过“分块”读取和写入来提高效率的地方。