mixing cout and printf for faster output
After performing some tests I noticed that printf
is much faster than cout
. I know that it's implementation dependent, but on my Linux box printf
is 8x faster. So my idea is to mix the two printing methods: I want to use cout
for simple prints, and I plan to use printf
for producing huge outputs (typically in a loop). I think it's safe to do as long as I don't forget to flush before switching to the other method:
cout << "Hello" << endl;
cout.flush();
for (int i=0; i<1000000; ++i) {
printf("World!\n");
}
fflush(stdout);
cout << "last line" << endl;
cout << flush;
Is it OK like that?
Update: Thanks for all the precious feedbacks. Summary of the answers: if you want to avoid tricky solutions, simply stick with cout
but don't use endl
since it flushes the buffer implicitly (slowing the process down). Use "\n"
instead. It can be interesting if you produce large outputs.
The direct answer is that yes, that's okay.
A lot of people have thrown around various ideas of how to improve speed, but there seems to be quite a bit of disagreement over which is most effective. I decided to write a quick test program to get at least some idea of which techniques did what.
#include <iostream>
#include <string>
#include <sstream>
#include <time.h>
#include <iomanip>
#include <algorithm>
#include <iterator>
#include <stdio.h>
char fmt[] = "%s\n";
static const int count = 3000000;
static char const *const string = "This is a string.";
static std::string s = std::string(string) + "\n";
void show_time(void (*f)(), char const *caption) {
clock_t start = clock();
f();
clock_t ticks = clock()-start;
std::cerr << std::setw(30) << caption
<< ": "
<< (double)ticks/CLOCKS_PER_SEC << "\n";
}
void use_printf() {
for (int i=0; i<count; i++)
printf(fmt, string);
}
void use_puts() {
for (int i=0; i<count; i++)
puts(string);
}
void use_cout() {
for (int i=0; i<count; i++)
std::cout << string << "\n";
}
void use_cout_unsync() {
std::cout.sync_with_stdio(false);
for (int i=0; i<count; i++)
std::cout << string << "\n";
std::cout.sync_with_stdio(true);
}
void use_stringstream() {
std::stringstream temp;
for (int i=0; i<count; i++)
temp << string << "\n";
std::cout << temp.str();
}
void use_endl() {
for (int i=0; i<count; i++)
std::cout << string << std::endl;
}
void use_fill_n() {
std::fill_n(std::ostream_iterator<char const *>(std::cout, "\n"), count, string);
}
void use_write() {
for (int i = 0; i < count; i++)
std::cout.write(s.data(), s.size());
}
int main() {
show_time(use_printf, "Time using printf");
show_time(use_puts, "Time using puts");
show_time(use_cout, "Time using cout (synced)");
show_time(use_cout_unsync, "Time using cout (un-synced)");
show_time(use_stringstream, "Time using stringstream");
show_time(use_endl, "Time using endl");
show_time(use_fill_n, "Time using fill_n");
show_time(use_write, "Time using write");
return 0;
}
I ran this on Windows after compiling with VC++ 2013 (both x86 and x64 versions). Output from one run (with output redirected to a disk file) looked like this:
Time using printf: 0.953
Time using puts: 0.567
Time using cout (synced): 0.736
Time using cout (un-synced): 0.714
Time using stringstream: 0.725
Time using endl: 20.097
Time using fill_n: 0.749
Time using write: 0.499
As expected, results vary, but there are a few points I found interesting:
- printf/puts are much faster than cout when writing to the NUL device
- but cout keeps up quite nicely when writing to a real file
- In my testing, fill_n is about as fast as anything else
I've recently edited the code to force a call to printf
. Anders Kaseorg was kind enough to point out--that g++
recognizes the specific sequence printf("%s\n", foo);
is equivalent to puts(foo);
, and generates code accordingly (i.e., generates code to call puts
instead of printf
). Moving the format string to a global array, and passing that as the format string produces identical output, but forces it to be produced via printf
instead of puts
. Of course, it's possible they might optimize around this some day as well, but at least for now (g++ 5.1) a test with g++ -O3 -S
confirms that it's actually calling printf
(where the previous code compiled to a call to puts
).
Sending std::endl
to the stream appends a newline
and flushes the stream. The subsequent invocation of cout.flush()
is superfluous. If this was done when timing cout
vs. printf
then you were not comparing apples to apples.
By default, the C and C++ standard output streams are synchronised, so that writing to one causes a flush of the other, so explicit flushes are not needed.
Also, note that the C++ stream is synced to the C stream.
Thus it does extra work to stay in sync.
Another thing to note is to make sure you flush the streams an equal amount. If you continuously flush the stream on one system and not the other that will definitely affect the speed of the tests.
Before assuming that one is faster than the other you should:
- un-sync C++ I/O from C I/O (see sync_with_stdio() ).
- Make sure the amount of flushes is comparable.
You can further improve the performance of printf
by increasing the buffer size for stdout
:
setvbuf (stdout, NULL, _IOFBF, 32768); // any value larger than 512 and also a
// a multiple of the system i/o buffer size is an improvement
The number of calls to the operating system to perform i/o is almost always the most expensive component and performance limiter.
Of course, if cout
output is intermixed with stdout
, the buffer flushes defeat the purpose an increased buffer size.