2

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.

Richard
  • 56,349
  • 34
  • 180
  • 251
  • possible duplicate of [C++ - endl and flushing the buffer](http://stackoverflow.com/questions/4751972/c-endl-and-flushing-the-buffer) – Linga Jan 15 '14 at 04:34
  • Important to note that this is OS/terminal specific. There is nothing in the spec which requires a flush on newline. – Ed S. Jan 15 '14 at 04:34
  • 6
    @ling.s: I fail to see how this question is a duplicate of the one you linked to. – Ed S. Jan 15 '14 at 04:35
  • 1
    I may be wrong about this, but I suspect that `cout`, by writing to `stdout`, will implicitly be opened in text mode and therefore do the character conversion necessary to convert `\n` to the right line ending. I can't find anything confirming this, though, but I suspect that writing `\n` is totally fine and portable. – templatetypedef Jan 15 '14 at 04:37
  • Just curious... if you're writing that many lines quickly... how can the user even read them? What's the point? stdout is line buffered because it's assumed to be _interactive_. If it's not then why not simply write somewhere else? – Ed S. Jan 15 '14 at 04:40
  • @EdS., the user may not be able to read individual lines, but the user can see patterns and trends in large numbers of lines. – Richard Jan 15 '14 at 04:42
  • @Ed The standard does not require a flush on '\n'. But it does on `endl`. This is not OS specific. – Alan Stokes Jan 15 '14 at 04:43
  • 2
    See this answer: http://stackoverflow.com/a/213977/1411457 – harmic Jan 15 '14 at 04:45
  • @AlanStokes: Yes, I know that. I was referring to the newline suggestion. – Ed S. Jan 15 '14 at 04:50
  • [This question](https://stackoverflow.com/questions/796865/can-i-stop-stdcout-flushing-on-n) may, however, be a duplicate. – Richard Jan 15 '14 at 04:58
  • And the rabbit whole goes [deeper](https://stackoverflow.com/questions/3857052/why-is-printing-to-stdout-so-slow-can-it-be-sped-up). – Richard Jan 15 '14 at 05:06
  • Problem can be solved by avoiding using `std::ostream` period. – Slava Sep 29 '16 at 13:38
  • 1
    "I do believe that endl is killing me" you should measure rather than believe, you may be surprised. – Slava Sep 29 '16 at 13:42

5 Answers5

9

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 4
    That's not really the question though. he wants to prevent flushes. Many platforms will also flush if they see a newline. – Ed S. Jan 15 '14 at 04:39
  • It seems to me this exactly answers the question. You avoid the flush by just writing '\n', and you don't lose any portability. – Alan Stokes Jan 15 '14 at 04:45
  • 2
    @AlanStokes: There is no guarantee that a newline won't cause a flush. I did miss what he was getting at at first glance though. I can't find any bullet proof way to do this. Maybe write to `cerr` instead? Hackish, but.... – Ed S. Jan 15 '14 at 04:46
  • 1
    @Ed And no reason why it would. But *that* wasn't the question. And as it happens `cerr` flushes after every write. – Alan Stokes Jan 15 '14 at 04:47
  • @AlanStokes, "In many implementations, standard output is line-buffered, and writing '\n' causes a flush anyway" -- [Source](http://en.cppreference.com/w/cpp/io/manip/endl). – Shoe Jan 15 '14 at 04:48
  • 1
    @AlanStokes: Of course it is. "Performance is poor due to constant flushing of the output stream, how can I fix this?" I think it's reasonable to assume that he doesn't want a "solution" which may or may not work given the user's environment. – Ed S. Jan 15 '14 at 04:49
  • @EdS.: fair point regarding what was asked for - but FWIW most programs print to stdout without explicit flushing, and if the *terminal* happens to flush per line then it's rarely a problem as particularly long output is typically piped or redirected, e.g. to less, tail, a file, /dev/null etc.. – Tony Delroy Jan 15 '14 at 05:07
  • @TonyD: Agreed. I asked him in the comments if he really needed/wanted to throw so much data at the user. – Ed S. Jan 15 '14 at 05:13
7

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.

Zeta
  • 103,620
  • 13
  • 194
  • 236
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.

RichardPlunkett
  • 2,998
  • 14
  • 14
1

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"
laune
  • 31,114
  • 3
  • 29
  • 42
1

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;
}
David G
  • 94,763
  • 41
  • 167
  • 253
  • Note: I needed to create an `endl` function because of the lifetime dependencies between the buffer and the stream. Moreover, even if the buffer was static, how can we distinguish between an `std::endl` call and an arbitrary `flush()`? – David G Jan 16 '14 at 00:01