vde*_*ris 4 c++ optimization iterator loops vector
为了提高应用程序的性能,我们必须在开发阶段考虑循环优化技术.
我将向您展示一些不同的迭代方法std::vector<uint32_t> v
:
带索引的未优化循环:
uint64_t sum = 0;
for (unsigned int i = 0; i < v.size(); i++)
sum += v[i];
Run Code Online (Sandbox Code Playgroud)使用迭代器的未优化循环:
uint64_t sum = 0;
std::vector<uint32_t>::const_iterator it;
for (it = v.begin(); it != v.end(); it++)
sum += *it;
Run Code Online (Sandbox Code Playgroud)缓存std::vector::end
迭代器:
uint64_t sum = 0;
std::vector<uint32_t>::const_iterator it, end(v.end());
for (it = v.begin(); it != end; it++)
sum += *it;
Run Code Online (Sandbox Code Playgroud)预增量迭代器:
uint64_t sum = 0;
std::vector<uint32_t>::const_iterator it, end(v.end());
for (it = v.begin(); it != end; ++it)
sum += *it;
Run Code Online (Sandbox Code Playgroud)基于范围的循环:
uint64_t sum = 0;
for (auto const &x : v)
sum += x;
Run Code Online (Sandbox Code Playgroud)还有其他方法可以在C++中构建循环; 例如,使用std::for_each
,BOOST_FOREACH
等...
哪个是提高性能的最佳解决方案?为什么?
此外,在性能关键型应用程序中,展开循环可能很有用:我怎么能这样做?
没有硬性规定,因为它取决于实施.如果我几年前所做的措施是典型的,那么:关于唯一能产生影响的是缓存最终迭代器.无论容器和迭代器类型如何,预修复或后修复都没有区别.
当时,我没有测量索引(因为我也在比较不同类型容器的迭代器,而不是所有支持索引).但我猜想如果你使用索引,你也应该缓存结果v.size()
.
当然,这些措施是针对一个系统上的一个编译器(g ++),具有特定的硬件.您可以了解您的环境的唯一方法是衡量自己.
请注意:您确定已启用完全优化.我的测量显示3和4之间没有差异,我怀疑今天的commpilers优化程度较低.
这里的优化对于实际内联函数非常重要.如果它们不是,则后递增确实需要一些额外的复制,并且通常还需要额外的函数调用(对迭代器的复制构造函数).然而,一旦函数被内联,编译器就可以很容易地看到所有这些都是不必要的,并且(至少当我尝试它时)在两种情况下都生成完全相同的代码.(无论如何,我会使用预增量.不是因为它有所不同,而是因为如果你不这样做,一些白痴会声称它会,尽管你采取了措施.或者他们可能不是白痴,但只是使用一个特别愚蠢的编译器.)
说实话,当我进行测量时,我很惊讶缓存最终迭代器产生了不同,即使对于矢量,其中前后增量之间没有区别,即使对于迭代迭代器也没有区别.毕竟,end()
也是内联的; 实际上,我测试中使用的每个函数都是内联的.
至于展开循环:我可能会做这样的事情:
std::vector<uint32_t>::const_iterator current = v.begin();
std::vector<uint32_t>::const_iterator end = v.end();
switch ( (end - current) % 4 ) {
case 3:
sum += *current ++;
case 2:
sum += *current ++;
case 1:
sum += *current ++;
case 0:
}
while ( current != end ) {
sum += current[0] + current[1] + current[2] + current[3];
current += 4;
}
Run Code Online (Sandbox Code Playgroud)
(这是因子4.如果需要,您可以轻松增加它.)