为了提高应用程序的性能,我们必须在开发阶段考虑循环优化技术。
我想向您展示一些不同的方法来迭代一个简单的 std::vector<uint32_t> v
:
带有索引的未优化循环:
uint64_t sum = 0; for (unsigned int i = 0; i < v.size(); i++) sum += v[i];
带有迭代器的未优化循环:
uint64_t sum = 0; std::vector<uint32_t>::const_iterator it; for (it = v.begin(); it != v.end(); it++) sum += *it;
缓存
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;
预增量迭代器:
uint64_t sum = 0; std::vector<uint32_t>::const_iterator it, end(v.end()); for (it = v.begin(); it != end; ++it) sum += *it;
基于范围的循环:
uint64_t sum = 0; for (auto const &x : v) sum += x;
在 C++ 中还有其他构建循环的方法;例如使用 std::for_each
, BOOST_FOREACH
等等……
在您看来,提高性能的最佳方法是什么?为什么?
此外,在性能关键型应用程序中,解开循环可能很有用:同样,您会建议哪种方法?
最佳答案
没有硬性规定,因为它取决于 执行。如果我几年前采取的措施是 然而,典型的:关于唯一有所作为的东西 正在缓存结束迭代器。修复前或修复后不会 差异,与容器和迭代器类型无关。
当时,我没有衡量索引(因为我在比较
不同类型容器的迭代器,但不是全部
支持索引)。但我猜如果你使用索引,
您还应该缓存 v.size()
的结果。
当然,这些措施是针对一个编译器 (g++) 的 系统,具有特定的硬件。你可以知道的唯一方法 你的环境就是衡量你自己。
请注意:您确定已开启全面优化吗? 我的措施显示 3 和 4 之间没有区别,我怀疑 今天编译器优化得更少。
这里的优化非常重要 函数实际上是内联的。如果他们不是, 后增量确实需要一些额外的复制,并且 通常需要额外的函数调用(到拷贝 迭代器的构造函数)也是如此。一旦功能是 然而,内联,编译器可以很容易地看到这一切都是 一个不必要的,并且(至少当我尝试它时)准确地生成 两种情况下的代码相同。 (我会使用预增量 反正。不是因为它有所不同,而是因为如果你 不要,一些白痴会声称它会,尽管 你的措施。或者也许他们不是白痴,而只是在使用 一个特别愚蠢的编译器。)
说实话,当我测量的时候,我很惊讶
缓存结束迭代器会有所不同,即使对于
vector ,因为之前和之前没有区别
后增量,即使对于映射的反向迭代器也是如此。
毕竟,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;
}
(这是 4 的因数。如果 必要的。)
关于c++ - C++中的循环优化技术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18213565/