Effect of sync_with_stdio(false) on C++ I/O Speed
Calling std::ios_base::sync_with_stdio(false) is a
standard optimization technique in C++ that significantly improves the
execution speed of input and output operations. By disabling the
synchronization between C++ standard streams and standard C streams, the
program avoids redundant overhead and enables independent,
high-performance buffering. This article explains the underlying
mechanism of this function, its direct performance impact, and the
essential considerations required when using it.
The Default Synchronization Mechanism
By default, standard C++ streams (std::cin,
std::cout, std::cerr, std::clog)
synchronize their underlying buffers with the corresponding standard C
streams (stdin, stdout, stderr).
This synchronization guarantees that developers can freely mix C-style
I/O functions (such as printf and scanf) with
C++ stream operations without unexpected ordering issues.
To maintain this synchronization, standard C++ streams bypass their
own internal buffering strategies or route operations directly through
the C runtime library. This introduces substantial per-operation
overhead, including redundant function calls and synchronization checks,
causing std::cin and std::cout to run
considerably slower than raw C functions.
How
sync_with_stdio(false) Improves Speed
When you invoke std::ios_base::sync_with_stdio(false)
before performing any I/O operations, the program severs the connection
between the C and C++ stream buffers:
- Independent Buffering: C++ streams activate their own internal buffers, allowing them to read and write large blocks of data at once rather than processing small chunks or individual characters to keep pace with C streams.
- Reduced System Calls: By accumulating operations in memory-backed C++ buffers, the number of expensive system-level read and write calls decreases dramatically.
- Elimination of Synchronization Overhead: The runtime no longer verifies the state of C streams prior to executing a C++ stream operation.
In practice, this optimization often makes std::cin and
std::cout just as fast as—and frequently faster
than—scanf and printf. In I/O-intensive
scenarios, such as reading millions of integers or parsing large text
datasets, processing time can drop from several seconds to a fraction of
a second.
Combining with
cin.tie(nullptr)
For maximum efficiency,
std::ios_base::sync_with_stdio(false) is frequently paired
with std::cin.tie(nullptr).
By default, std::cin is tied to std::cout,
meaning that std::cout is automatically flushed whenever an
input operation is requested on std::cin. While this
ensures user prompts appear before blocking for input in interactive
programs, it incurs a severe performance penalty in batch processing.
Untying the streams via std::cin.tie(nullptr) eliminates
these automatic flushes, further compounding the speed gains achieved by
disabling synchronization.
Critical Considerations
- Do Not Mix I/O Styles: Once synchronization is
disabled, mixing C functions (
printf,scanf,puts,getchar) with C++ streams (std::cout,std::cin) produces undefined or out-of-order output because each system maintains its own separate buffer. - Avoid
std::endl: Usingstd::endlinserts a newline character and forces a buffer flush. To preserve the speed advantages of unsynchronized I/O, use the\ncharacter instead, allowing the buffer to flush naturally when full. - Early Execution: The call must be executed before any input or output operations occur on the streams to prevent undefined behavior.