Search code examples
c++coutostream

c++ cout redirected to file works slower than using ofstream


I have an application that have to iterate over every character (to check some special cases) and write it to a stream using ostream put method.

When writing the ostream* points to a file stream, it executes magnificently faster than when ostream* points to cout which is redirected to a file.

In this (https://stackoverflow.com/a/1697906/12074577) answer I saw that probable using the fstream will be faster, due to one more layer of buffering compared to cout. I thought that when I know that the output is going to cout, I can go through a string buffer, and when the buffer is full, append it to cout. This way I obtain another layer of buffering and performance will improve.

So I have a test here of writing 32 million rows, each row is a string of ten characters. I write them using cout, fstream, and stringbuffer that is later appended to cout.


void print_to_ostream(ostream *out, string& ones)
{
    for (int i = 0; i < 32000000; ++i){

            const char* ones_char = ones.c_str();
            for (int j = 0; j < ones.size(); ++j ){
                out->put(ones_char[j]);
            }
        }
}

int main(void){
    string ones ="1111111111";


    ostream *out = &cout;
    size_t cout_time = 0;
    size_t file_time = 0;
    size_t cout_buffered_time = 0;

    // print cout using ostream
    mono_tick_timer time;
    print_to_ostream(out, ones);
    cout_time += time.tick();

    // write to file using ostream
    ofstream file("/tmp/test_file");
    out = &file;
    time.tick();
    print_to_ostream(out, ones);
    file_time += time.tick();

    // ***optional solution***
    // print to cout but passing through a string buffer
    stringstream buffer;
    out = &buffer;

    time.tick();
    print_to_ostream(out, ones);
    cout_buffered_time += time.tick();
    cout << buffer.str();
    size_t buf_to_cout = time.tick();


    std::cerr << "cout time: " <<  (double)cout_time / 1e6 << endl;
    std::cerr << "file time: " <<  (double)file_time / 1e6 << endl;
    std::cerr << "cout buffered time: " <<  (double)cout_buffered_time / 1e6 << endl;
    std::cerr << "buf_to_cout: " <<  (double)buf_to_cout / 1e6 << endl;

    return 0;

}

The results of running ./a.out > /tmp/test_times are as follow (milliseconds):

cout time: 4773.62
file time: 2391.52
cout buffered time: 2380.83
buf_to_cout: 131.615

My bottom line question is: is using stringstream as a buffer before appending everything to cout a good solution? Considering the fact that sometimes cout is redirected with large output to a file, and sometimes it's just being printed to the console?

Are they any negative side effects I didn't think about with this solution? Or there is a better one I didn't think about?


Solution

  • The global streams (e.g. std::cout) are sync_with_stdio by default, whereas std::ofstream is not:

    By default, all eight standard C++ streams are synchronized with their respective C streams.

    If the synchronization is turned off, the C++ standard streams are allowed to buffer their I/O independently, which may be considerably faster in some cases.

    Try turning it off with std::cout.sync_with_stdio(false);.