为什么 ifstream::read 比使用迭代器快得多?
Why is ifstream::read much faster than using iterators?
事实上,有很多方法可以将文件读入字符串。
两个常见的是使用 ifstream::read 直接读取字符串并使用 steambuf_iterators 和 std::copy_n:
使用ifstream::read:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
使用std::copy_n:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
std::copy_n(std::streambuf_iterator<char>(in),
contents.size(),
contents.begin();
许多基准测试表明第一种方法比第二种方法快得多(在我使用 g++-4.9 的机器上,使用 -O2 和 -O3 标志大约快 10 倍),我想知道可能是什么造成这种性能差异的原因。
read
是单个 iostream 设置(每个 iostream 操作的一部分)和对 OS 的单个调用,直接读入您提供的缓冲区。
迭代器通过重复提取单个 char
和 operator>>
来工作。由于缓冲区大小,这可能意味着更多 OS 调用,但更重要的是,它还意味着重复设置和拆除 iostream 哨兵,这可能意味着互斥锁,并且通常意味着一堆其他东西。此外,operator>>
是格式化操作,而 read
是未格式化的,这是每个操作的额外设置开销。
编辑: 眼睛疲劳看到了 istream_iterator 而不是 istreambuf_iterator。当然 istreambuf_iterator 不做格式化输入。它在 streambuf 上调用 sbumpc 或类似的东西。仍然有很多调用,并且使用了可能比整个文件还小的缓冲区。
事实上,有很多方法可以将文件读入字符串。 两个常见的是使用 ifstream::read 直接读取字符串并使用 steambuf_iterators 和 std::copy_n:
使用ifstream::read:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
使用std::copy_n:
std::ifstream in {"./filename.txt"};
std::string contents;
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
std::copy_n(std::streambuf_iterator<char>(in),
contents.size(),
contents.begin();
许多基准测试表明第一种方法比第二种方法快得多(在我使用 g++-4.9 的机器上,使用 -O2 和 -O3 标志大约快 10 倍),我想知道可能是什么造成这种性能差异的原因。
read
是单个 iostream 设置(每个 iostream 操作的一部分)和对 OS 的单个调用,直接读入您提供的缓冲区。
迭代器通过重复提取单个 char
和 operator>>
来工作。由于缓冲区大小,这可能意味着更多 OS 调用,但更重要的是,它还意味着重复设置和拆除 iostream 哨兵,这可能意味着互斥锁,并且通常意味着一堆其他东西。此外,operator>>
是格式化操作,而 read
是未格式化的,这是每个操作的额外设置开销。
编辑: 眼睛疲劳看到了 istream_iterator 而不是 istreambuf_iterator。当然 istreambuf_iterator 不做格式化输入。它在 streambuf 上调用 sbumpc 或类似的东西。仍然有很多调用,并且使用了可能比整个文件还小的缓冲区。