问题
My program prints a large number of short lines to cout
.
As a slightly contrived example, my lines look a little like this:
cout<<"The variable's value is: "<<variable<<endl;
I'd like the program to run fast and I do believe that endl
is killing me because it initiates a buffer flush on cout
every time it is used.
Now, some folks on the internet have said that I could do this instead:
cout<<"The variable's value is: "<<variable<<"\n";
But this does not seem like a good solution because endl
abstracts the particular system-specific ways an end line might be specified, where as \n
does not. This also seems like a poor solution because, should I need buffering in the future, I would then have to modify the whole code base.
Therefore, I ask, is there a way to disable the buffer-flushing aspect of endl
?
EDIT
Further digging seems to indicate that both endl
and \n
respect the various ways an OS might choose to end it's lines. It also seems that the output stream detects if it's in a potentially interactive situation and buffers and flushes accordingly. Therefore: the problem may be solved by manually telling the output stream to perform aggressive buffering... if I can figure out how to do that.
回答1:
endl abstracts the particular system-specific ways an end line might be specified, where as \n does not".
std::endl
is defined to output '\n'
followed by a flush. The correct abstraction of the system-specific newline thingy is just '\n'
.
To prevent flushes, one just doesn't use std::endl
. In addition, the standard output may be line-buffered if it is or may be connected to an interactive device, in this case the newline character will flush the stream. If that's an issue, use an ofstream
connected to a named file. I think on Unix-like systems line buffering only happens when the standard output is a terminal.
回答2:
endl
flushes. If you don't want that behaviour, don't use endl
. If you want to change your code easily, use your own manipulator:
inline std::ostream& myendl( std::ostream& os ){
os.put(os.widen('\n'));
return os;
}
That way you can easily change the behaviour of your myendl
at one place.
回答3:
According to http://en.cppreference.com/w/cpp/io/manip/endl
endl:: Inserts a endline character into the output sequence os and flushes it as if by calling os.put(os.widen('\n'))
followed by os.flush()
.
So it appears you want to just write os.put(os.widen('\n'))
, which should, from this definition be safe and portable and correct, as well as meeting your primary needs.
回答4:
There is std::nounitbuf which is documented to have some effect in this matter. However, I didn't notice any difference. To bypass all of the ostream's ideas of when or when not to flush I tried this:
std::ostringstream oss;
// std::cout << std::nounitbuf;
for( int i = 0; i < 1000000; i++ ){
// std::cout << "Test " << "file" << '\n';
oss << "Test " << "file" << '\n';
}
std::cout << oss.str();
This improved execution time from ~33 sec to ~25csec.
IF your output goes to an xterm, your execution speed is severly limited by xterm's work to do scrolling etc. If you use a pipeline to filter out unnecessary lines you'll see a dramatic increase in speed, e.g.
./program | grep -v "The variable"
回答5:
If flushing is the problem, you can implement a stream buffer that overrides the sync()
member function to only flush to the external device if you specify so. It also obligates creating your own manipulators flush_on_endl
and noflush_on_endl
if you intend to change these preferences throughout the program.
#include <iostream>
static int disable() {
static int index(std::ios_base::xalloc());
return index;
}
class save_buffer
{
public:
save_buffer(std::ios& other)
: str(other), buf(other.rdbuf())
{ }
~save_buffer() { str.rdbuf(buf); }
private:
std::ios& str;
std::streambuf* buf;
};
class syncing_buffer_optional : public std::streambuf, private save_buffer
{
public:
syncing_buffer_optional(std::ostream& other)
: save_buffer(other),
buf(other.rdbuf()),
disable_sync(other.iword(disable()))
{ }
std::streambuf::int_type overflow(std::streambuf::int_type c)
{
buf->sputc(c);
return 0;
}
int sync()
{
return disable_sync? 0: buf->pubsync();
}
private:
std::streambuf* buf;
bool disable_sync;
};
std::ostream& flush_on_endl(std::ostream& os)
{
os.iword(disable()) = false;
return os;
}
std::ostream& noflush_on_endl(std::ostream& os)
{
os.iword(disable()) = true;
return os;
}
std::ostream& endl(std::ostream& os)
{
syncing_buffer_optional eb(os);
os.rdbuf(&eb);
return os << std::endl;
}
int main()
{
std::cout << noflush_on_endl << endl;
}
来源:https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush