Question:
By default reading with cin
is excruciatingly slow compared to its scanf
counterpart… when logic tells us it shouldn't:
- With
cin
a direct call is made to the function that knows what the type of the destination variable is. - With
scanf
the function must read the format string (with dozens of possibilities) to know how to interpret the input and then process it.
However, with a simple example it is easy to see that reality is different:
#include <iostream>
#include <chrono>
#include <string>
void cinFunc()
{
int N;
for( int i=0; i<100000; i++)
std::cin >> N;
}
void scanfFunc()
{
int N;
for( int i=0; i<100000; i++)
scanf(" %d",&N);
}
template<typename Func>
void Test(std::string const& title, Func f)
{
auto start = std::chrono::steady_clock::now();
f();
auto end = std::chrono::steady_clock::now();
auto diff = end - start;
std::cout << "Test " << title << ":\t" << std::chrono::duration<double, std::milli>(diff).count() << " ms\n";
}
int main()
{
Test("cin",cinFunc);
Test("scanf",scanfFunc);
return EXIT_SUCCESS;
}
The program is run with a file containing 200,000 1-digit integers separated by a space, and the results speak for themselves:
Test cin: 64.7967 ms
Test scanf: 49.855 ms
What is the reason that C++'s own reading is so slow? How can this situation be corrected?
Answer:
By default iostream
is synchronized with stdio
to ensure that the standard input and output functions of both C
and C++
share a single buffer, since without synchronization both would have independent buffers, this would cause problems like:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
cout << "Hola";
printf("mundo");
cout << "adios";
}
Without synchronization you will never know if you will get Holaadiosmundo
or Holamundoadios
or adiosholamundo
since both printf
and cout
have different buffers so the order is undefined. Unfortunately the sync issue introduces a significant performance penalty for iostream
, but it is possible to disable it if you don't intend to mix stdio
and iostream
.
ios_base::sync_with_stdio(false);
This would give a significant performance boost even better than stdio
.