我使用i)std::none_of
循环,ii)基于范围的for
循环和iii)迭代器,将for
的性能与三种不同的手动实现进行基准测试。令我惊讶的是,我发现虽然所有三个手动实现大致相同,但std::none_of
明显更快。我的问题是 - 为什么会这样?
我使用Google基准测试库并使用-std=c++14 -O3
编译。运行测试时,我将进程的关联性限制为单个处理器。我使用GCC 6.2得到以下结果:
Benchmark Time CPU Iterations
--------------------------------------------------------
benchmarkSTL 28813 ns 28780 ns 24283
benchmarkManual 46203 ns 46191 ns 15063
benchmarkRange 48368 ns 48243 ns 16245
benchmarkIterator 44732 ns 44710 ns 15698
在Clang 3.9上,虽然速度差异较小,但std::none_of
也比手动for
循环快。这是测试代码(仅包括用于简洁的循环手册):
#include <algorithm>
#include <array>
#include <benchmark/benchmark.h>
#include <functional>
#include <random>
const size_t N = 100000;
const unsigned value = 31415926;
template<size_t N>
std::array<unsigned, N> generateData() {
std::mt19937 randomEngine(0);
std::array<unsigned, N> data;
std::generate(data.begin(), data.end(), randomEngine);
return data;
}
void benchmarkSTL(benchmark::State & state) {
auto data = generateData<N>();
while (state.KeepRunning()) {
bool result = std::none_of(
data.begin(),
data.end(),
std::bind(std::equal_to<unsigned>(), std::placeholders::_1, value));
assert(result);
}
}
void benchmarkManual(benchmark::State & state) {
auto data = generateData<N>();
while (state.KeepRunning()) {
bool result = true;
for (size_t i = 0; i < N; i++) {
if (data[i] == value) {
result = false;
break;
}
}
assert(result);
}
}
BENCHMARK(benchmarkSTL);
BENCHMARK(benchmarkManual);
BENCHMARK_MAIN();
请注意,使用随机数生成器生成数据无关紧要。只需将i
- th元素设置为i
并检查是否包含值N + 1
,我就会得到相同的结果。
答案 0 :(得分:3)
经过一番调查后,我会尽力回答自己的问题。正如Kerrek SB所建议的,我查看了生成的汇编代码。最重要的是,与其他三个版本相比,GCC 6.2在展开std::none_of
中隐含的循环方面做得更好。
GCC 6.2:
std::none_of
展开4次 - &gt; 〜30微秒for
,范围for
和迭代器根本没有展开 - &gt; 〜45μs根据Corristo的建议,结果是编译器依赖 - 这非常有意义。 Clang 3.9展开除for
范围之外的所有循环,但程度不同。
Clang 3.9
for
展开5次 - &gt; 〜为35μsfor
根本没有展开 - &gt; 〜60μs的 所有代码都是使用-std=c++14 -O3
编译的。