缓冲区刷新:"\n" vs. std::endl
在第三方库中,向流中写入'\n'的含义可能与写入std::endl/std::flush不同。例如,在当前项目中,我正在使用基于ostream的日志记录器。该记录器使用std::stringstream的功能进行输出格式化,但是已经重写了用于刷新的操作符。这样可以在日志中写入'\n'而不进行刷新,从而简化了代码。
以下是一个伪代码示例:
class MyStream { // [cut] std::stringstream m_buffer; // [cut] }; // friends: templateMyStream& operator<<(MyStream& stream, const Printable& value) { stream.m_buffer << value; } typedef decltype(std::flush) TManipulator; template <> MyStream& operator<<(MyStream& stream, const TManipulator& manipulator) { if ( manipulator == std::flush || manipulator == std::endl ) stream.sendLogLine(); else stream.m_buffer << manipulator; } // usage sample void main() { getLoggerStream() << "hello" << std::endl; }
P.S. 我不喜欢子类化std::stringstream,所以MyStream是一个适配器。如果我想要使'\n'刷新,我应该重新实现更多功能,包括char*、std::string和其他特化类型。
使用'\n'不会刷新缓冲区,相比使用std::endl确实更快。
在典型的I/O中,在写入到目标设备之前会对输出进行缓冲。这样,当写入到访问速度较慢的设备(如文件)时,不需要在每个字符后都访问设备。刷新操作会将缓冲区"刷新"到设备上,从而导致明显的性能开销。
对于一些[一般来说]非常小的"faster"值来说 😉
:好吧,当向文件输出大量数据时,它实际上可能会降低性能(当我在CSV中写入数十兆字节的数据时,我曾经遇到过这种情况)。
确实,我没有考虑到这个反向情况 🙁
:另一方面,iostream不是输出内容的最快方式,所以还会有其他许多因素对性能产生负面影响。
:iostream的设计非常糟糕,但在g++
实现中,我发现它在某些情况下稍微比C stdio快一点。