众所周知,ios_base::sync_with_stdio(false)
将通过阻止同步b / w C和C ++ I / O来帮助<iostream>
中cin和cout的性能。但是,我很好奇它是否在<fstream>
中有任何不同。
我使用GNU C ++ 11和以下代码(使用和不使用ios_base::sync_with_stdio(false)
代码段)运行了一些测试:
#include <fstream>
#include <iostream>
#include <chrono>
using namespace std;
ofstream out("out.txt");
int main() {
auto start = chrono::high_resolution_clock::now();
long long val = 2;
long long x=1<<22;
ios_base::sync_with_stdio(false);
while (x--) {
val += x%666;
out << val << "\n";
}
auto end = chrono::high_resolution_clock::now();
chrono::duration<double> diff = end-start;
cout<<diff.count()<<" seconds\n";
return 0;
}
结果如下:
With sync_with_stdio(false): 0.677863 seconds (average 3 trials)
Without sync_with_stdio(false): 0.653789 seconds (average 3 trials)
这是预期的吗?是否有理由使用sync_with_stdio(false)几乎相同(如果不是更慢)的速度?
感谢您的帮助。
答案 0 :(得分:0)
sync_with_stdio()
的想法是允许将输入和输出混合到标准流对象(C 和 stdin
中的 stdout
、stderr
和 std::cin
, std::cout
、std::cerr
和 std::clog
以及它们在 C++ 中对应的宽字符流),而无需担心字符会被缓冲在相关对象的任何缓冲区中。实际上,通过 std::ios_base::sync_with_stdio(true)
,C++ IOStreams 不能使用它们自己的缓冲区。在实践中,这通常意味着 std::streambuf
级别的缓冲完全被禁用。但是,没有缓冲区 IOStreams 相当昂贵,因为它们处理可能涉及多个虚拟函数调用的单个字符。本质上,您从 std::ios_base::sync_with_stdio(false)
获得的加速是允许 C 和 C++ 库使用自己的缓冲区。
另一种方法可能是在 C 和 C++ 库设施之间共享缓冲区,例如,通过在更强大的 C++ 库设施之上构建 C 库设施(在人们抱怨这将是一个糟糕的主意之前,使CI/O 更慢:如果正确实现标准 C++ 库 IOStreams,这实际上根本不是真的)。我不知道任何使用它的非实验性实现。使用此设置 std::ios_base::sync_with_stdio(value)
根本不会产生任何影响。
IOStreams 的典型实现为标准流对象使用不同的流缓冲区,而这些对象用于文件流。部分原因可能是标准流对象通常不是使用名称打开的,而是使用其他一些标识它们的实体打开的,例如,UNIX 系统上的文件描述符,它需要一个“后门”接口来允许使用 {{1 }} 用于标准流对象。然而,至少 Dinkumware 的标准 C++ 库的早期实现(例如,使用 MSVC++)使用 std::filebuf
作为标准流对象。这个 std::filebuf
实现只是 std::filebuf
的一个包装器,即,字面上实现了 C++ 标准所说的内容,而不是语义上的实现。一开始这已经是一个糟糕的想法,但是通过使用 FILE*
禁止所有文件流的 std::streambuf
级缓冲使情况变得更糟,因为该设置也会影响文件流。我不知道此 [性能] 问题是否已修复。 C/C++ 用户日志和/或 P.J.Plauger 的“[草案] 标准 C++ 库”中的旧问题应该显示对此实现的讨论。
tl;dr:根据标准 std::ios_base::sync_with_stdio(true)
仅更改标准流对象的约束以使其使用更快。它是否有其他影响取决于 IOStream 的实现,并且至少有一个(Dinkumware)发挥了作用。