C++ endl 并刷新缓冲区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4751972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
endl and flushing the buffer
提问by Simplicity
In the C++ primerbook, in chapter (1), it mentions the following:
在C++ 入门书的第 (1) 章中,它提到了以下内容:
endl is a special value, called a manipulator, that when written to an output stream has the effect of writing a newline to the output and ?ushing the buffer associated with that device. By ?ushing the buffer, we ensure that the user will see the output written to the stream immediately.
endl 是一个特殊值,称为操纵器,当写入输出流时,它的作用是将换行符写入输出并 刷新与该设备关联的缓冲区。通过刷新缓冲区,我们确保用户将立即看到写入流的输出。
What is meant by "flushing the buffer" here?
这里的“刷新缓冲区”是什么意思?
回答by Benjamin Lindley
Output is generally buffered before it's written to the intended device. That way, when writing to slow to access devices(like files), it doesn't have to access the device after every single character.
输出通常在写入目标设备之前进行缓冲。这样,当写入慢速访问设备(如文件)时,它不必在每个字符后访问设备。
Flushing means emptying the buffer and actually writing it to the device.
刷新意味着清空缓冲区并将其实际写入设备。
回答by wich
C++'s iostreams are buffered, that means that when you output to an ostream, the content will not immediately go to what is behind the stream, e.g. stdout in the case of cout. The implementation of the stream determines when to actually send the buffered part of the stream out. This is done for reasons of efficiency, it would be very inefficient to write to a network or disk stream byte by byte, by buffering this problem is solved.
C++ 的 iostream 是缓冲的,这意味着当您输出到 ostream 时,内容不会立即转到流后面的内容,例如 cout 中的 stdout。流的实现决定了何时实际将流的缓冲部分发送出去。这样做是出于效率的考虑,逐字节写入网络或磁盘流会非常低效,通过缓冲解决了这个问题。
This does however mean that when you write say debug messages to a log file and your program crashes you may lose part of the data you wrote to the log file through the stream, as a part of the log may still be in the stream's buffer and not yet written to the actual file. To prevent this from happening you need to make the stream flush its buffers either by an explicit flush method call, or by using the convenience of endl.
然而,这确实意味着当您将调试消息写入日志文件并且程序崩溃时,您可能会丢失通过流写入日志文件的部分数据,因为日志的一部分可能仍在流的缓冲区中,并且尚未写入实际文件。为了防止这种情况发生,您需要通过显式刷新方法调用或使用 endl 的便利来使流刷新其缓冲区。
If however you're just writing to a file regularly you should use \n instead of endl to prevent the stream from unnecessarily flushing the stream every line reducing your performance.
但是,如果您只是定期写入文件,则应使用 \n 而不是 endl 以防止流不必要地刷新流每一行,从而降低性能。
Edited to include this note:
编辑以包含此注释:
cin and cout have a special relationship, where reading from cin will automatically flush cout beforehand. This makes sure that the e.g. the prompt you wrote to cout will actually be seen by the user before the read from cin is waiting for input. Hence, even in cout you don't normally need endl but can use \n instead. You can create such relationships between other streams as well by tying them together.
cin 和 cout 有一个特殊的关系,从 cin 读取会预先自动刷新 cout。这可以确保在从 cin 读取的内容等待输入之前,用户实际上会看到例如您写给 cout 的提示。因此,即使在 cout 中,您通常也不需要 endl 但可以使用 \n 代替。您也可以通过将其他流绑定在一起来在其他流之间创建此类关系。
回答by nobar
What is meant by "flushing the buffer" here?
这里的“刷新缓冲区”是什么意思?
std::endl
causes the data in the stream's internal staging memory (its "buffer") to be "flushed" (transferred) to the operating system. The subsequent behavior depends on what type of device the stream is mapped to, but in general, flushing will give the appearance that the data has been physically transferred to the associated device. A sudden loss of power, however, might defeat the illusion.
std::endl
导致流的内部暂存内存(其“缓冲区”)中的数据被“刷新”(传输)到操作系统。后续行为取决于流映射到的设备类型,但通常,刷新会显示数据已物理传输到相关设备。然而,突然失去力量可能会打破这种幻想。
This flushing involves some overhead(wasted time), and should therefore be minimized when execution speed is an important concern. Minimizing the overall impact of this overhead is the fundamental purpose of data buffering, but this goal can be defeated by excessive flushing.
这种刷新涉及一些开销(浪费时间),因此当执行速度是一个重要问题时应该最小化。最小化这种开销的总体影响是数据缓冲的基本目的,但这个目标可能会因过度刷新而失败。
Background information
背景资料
The I/O of a computing system is typically very sophisticated and composed of multiple abstraction layers. Each such layer may introduce a certain amount of overhead. Data buffering is a way of reducing this overhead by minimizing the number of individual transactions performed between two layers of the system.
计算系统的 I/O 通常非常复杂,由多个抽象层组成。每个这样的层可能会引入一定量的开销。数据缓冲是通过最小化在系统的两层之间执行的单个事务的数量来减少这种开销的一种方式。
CPU/memory system-level buffering (caching): For very high activity, even the random-access-memory system of a computer can become a bottleneck. To address this, the CPU virtualizes memory accesses by providing multilple layers of hidden caches (the individual buffers of which are called cache lines). These processor caches buffer your algorithm's memory writes (pursuant to a writing policy) in order to minimize redundant accesses on the memory bus.
Application-level buffering: Although it isn't always necessary, it is not uncommon for an application to allocate chunks of memory to accumulate output data before passing it to the I/O library. This provides the fundamental benefit of allowing for random accesses (if necessary), but a significant reason for doing this is that it minimizes the overhead associated with making library calls -- which may be substantially more time-consuming than simply writing to a memory array.
I/O library buffering: The C++ IO stream libraryoptionally manages a buffer for every open stream. This buffer is used, in particular, to limit the number of system callsto the operating system kernel because such calls tend to have some non-trivial overhead. This is the buffer which is flushed when using
std::endl
.operating system kernel and device drivers: The operating system routes the data to a specific device driver (or subsystem) based on what output device the stream is attached to. At this point, the actual behavior may vary widely depending on the nature and characteristics of that type of device. For example, when the device is a hard disk, the device driver might notinitiate an immediate transfer to the device, but rather maintain its own buffer in order to further minimize redundant operations (since disks, too, are most efficiently written to in chunks). In order to explicitly flush kernel-level buffers, it may be necessary to call a system-level function such as
fsync() on Linux
-- even closingthe associated stream, doesn't necessarily force such flush.Example output devices might include...
- a terminal on the local machine
- a terminal on a remote machine (via SSH or similar)
- data being sent to another application via pipes or sockets
- many variations of mass-storage devices and associated file-systems, which may be (again) locally attached or distributed via a network
hardware buffers: Specific hardware may contain its own memory buffers. Hard drives, for example, typically contain a disk bufferin order to (among other things) allow the physical writes to occur without requiring the system's CPU to be engaged in the entire process.
CPU/内存系统级缓冲(缓存):对于非常高的活动,即使是计算机的随机存取内存系统也可能成为瓶颈。为了解决这个问题,CPU 通过提供多层隐藏缓存(其中的单个缓冲区称为缓存线)来虚拟化内存访问。这些处理器缓存缓冲算法的内存写入(根据写入策略),以最大限度地减少内存总线上的冗余访问。
应用程序级缓冲:虽然并不总是必要的,但应用程序在将输出数据传递到 I/O 库之前分配内存块来累积输出数据的情况并不少见。这提供了允许随机访问(如有必要)的基本好处,但这样做的一个重要原因是它最大限度地减少了与进行库调用相关的开销——这可能比简单地写入内存数组更耗时.
I/O 库缓冲:C++ IO 流库可选择为每个打开的流管理一个缓冲区。该缓冲区特别用于限制对操作系统内核的系统调用数量,因为此类调用往往具有一些非平凡的开销。 这是在使用时刷新的缓冲区
std::endl
。操作系统内核和设备驱动程序:操作系统根据流所连接的输出设备将数据路由到特定的设备驱动程序(或子系统)。此时,实际行为可能会因该类型设备的性质和特征而有很大差异。例如,当设备是硬盘时,设备驱动程序可能不会立即启动到设备的传输,而是维护自己的缓冲区以进一步减少冗余操作(因为磁盘也最有效地以块的形式写入)。为了显式刷新内核级缓冲区,可能需要调用系统级函数,例如
fsync() on Linux
——即使关闭关联的流,也不一定强制执行此类刷新。示例输出设备可能包括...
- 本地机器上的终端
- 远程机器上的终端(通过 SSH 或类似方式)
- 数据通过管道或套接字发送到另一个应用程序
- 大容量存储设备和相关文件系统的许多变体,它们可能(再次)本地连接或通过网络分发
硬件缓冲区:特定硬件可能包含自己的内存缓冲区。例如,硬盘驱动器通常包含一个磁盘缓冲区,以便(除其他外)允许物理写入发生,而无需系统的 CPU 参与整个过程。
Under many circumstances, these various buffering layers tend to be (to a certain extent) redundant -- and therefore essentially overkill. However, the buffering at each layer canprovide a tremendous gain in throughput if the other layers, for whatever reason, fail to deliver optimum buffering with respect to the overhead associated with each layer.
在许多情况下,这些不同的缓冲层往往(在某种程度上)是多余的——因此基本上是矫枉过正。然而,如果其他层无论出于何种原因未能针对与每一层相关联的开销提供最佳缓冲,则每一层的缓冲可以提供吞吐量的巨大增益。
Long story short, std::endl
onlyaddressed the buffer which is managed by the C++ IO stream library for that particular stream. After calling std::endl
, the data will have been moved to kernel-level management, and what happens next with the data depends on a great many factors.
长话短说,std::endl
只解决了由 C++ IO 流库为该特定流管理的缓冲区。调用之后std::endl
,数据就会被转移到内核级管理,数据接下来会发生什么取决于很多因素。
How to avoid the overhead of std::endl
如何避免开销 std::endl
- Method 1: Don't use
std::endl
-- use'\n'
instead. - Method 2: Don't use
std::endl
-- use something like the following version instead...
- 方法一:不要用
std::endl
——'\n'
改用。 - 方法2:不要使用
std::endl
--使用类似以下版本的东西代替...
inline std::ostream & endl( std::ostream & os )
{
os.put( os.widen('\n') ); // http://en.cppreference.com/w/cpp/io/manip/endl
if ( debug_mode ) os.flush(); // supply 'debug_mode' however you want
return os;
}
In this example, you provide a custom endl
which can be called with-or-without invoking the internal call to flush()
(which is what forces the transfer to the operating system). Enabling the flush (with the debug_mode
variable) is useful for debugging scenarios where you want to be able to examine the output (for example a disk-file) when the program has terminated before cleanly closing the associated streams (which would have forced a final flush of the buffer).
在此示例中,您提供了一个自定义endl
,可以在调用或不调用内部调用的情况下调用它flush()
(这是强制传输到操作系统的原因)。启用刷新(使用debug_mode
变量)对于调试场景很有用,在这种情况下,您希望能够在程序终止时检查输出(例如磁盘文件),然后再干净地关闭关联的流(这将强制进行最终刷新)缓冲区)。
回答by CaptainDaVinci
When using std::cout
, the operand used after the output operator ( <<
) are stored in a buffer and are not displayed onto the stdin
(usually terminal, or the command prompt) until it comes across std::endl
or std::cin
, which causes the buffer to be flushed, in the sense, display/output the contents of the buffer onto the stdin
.
使用时std::cout
,在输出运算符 ( <<
)之后使用的操作数存储在缓冲区中,并且在stdin
遇到std::endl
or之前不会显示在(通常是终端或命令提示符)上std::cin
,这会导致缓冲区被刷新,在某种意义上,将缓冲区的内容显示/输出到stdin
.
Consider this program:
考虑这个程序:
#include <iostream>
#include <unistd.h>
int main(void)
{
std::cout << "Hello, world";
sleep(2);
std::cout << std::endl;
return 0;
}
The output obtained will be:
获得的输出将是:
after 2 seconds
2 秒后
Hello, World
你好,世界
回答by shubham ranjan
One simple code to show you the effects of buffered I/O in c++
一个简单的代码向您展示了在 C++ 中缓冲 I/O 的效果
Whatever input you provide is buffered and then passed on to the program variables in case of inputs.
您提供的任何输入都会被缓冲,然后在输入的情况下传递给程序变量。
Have a look at the code below:
看看下面的代码:
//program to test how buffered I/O can have unintended effects on our program
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a;
char c;
cin>>a;
cin>>c;
cout<<"the number is : "<<a;
cout<<"\nthe character is : "<<c;
}
here we have declared two variables one int and one char if we input the number as "12d34" this will cause the int variable to accept only 12 as value and it will discard the rest which will still be there in the buffer. And in the next input the char variable will automatically accept the value "d" without even asking you for any input
在这里,我们声明了两个变量,一个是 int,一个是 char,如果我们将数字输入为“12d34”,这将导致 int 变量仅接受 12 作为值,并且将丢弃仍将在缓冲区中的其余变量。在下一个输入中,char 变量将自动接受值“d”,甚至不要求您提供任何输入