在循环条件下重复求值表达式效率低吗?

Is it inefficient to repetitively evaluate expression in loop condition?

本文关键字:效率 表达式 循环 条件下      更新时间:2023-10-16

作为初学者,我经常看到循环条件包含函数调用和一些计算密集型表达式,如下所示(例如来自c++ primer,循环语句):

for(int *beg = begin(array); beg != end(array); ++beg) ;

我担心的是:由于在每次迭代中检查条件,在条件内计算表达式的代价不是很高吗(这里运行end()函数)?

首先,这实际上可能不会对性能产生可测量的影响:如果循环体花费数倍的时间(对于普通代码来说很常见),或者循环作为一个整体不是瓶颈,那么对循环条件的任何优化都是浪费的。

第二,end()的常用实现是内联的完美候选。一旦它被内联,因为end()必须没有副作用,迭代器结构受制于循环不变代码运动。在这两个转换之后,实际上与"手动优化"的版本没有区别,程序员无需额外的努力。

第三,即使第二点不适用,对于大多数代码来说,对于更简洁的代码来说,这是一个小代价,特别是对于初学者来说。同样的原因使得上面描述的优化变得微不足道,也使得人们应用相同的转换变得微不足道,如果需要

因为书籍是说教性的,可读性比性能更重要。对于初学者来说,如果不需要弄清楚优化技巧,就更容易掌握算法的原理!

在现实生活中这也是有道理的:end条件往往是复杂的,并且受到每次迭代的影响。因此,使结束条件易于理解并隐藏实现细节更安全,更易于维护。

如果性能真的很重要,首先想想B.Kernighan的声明:"不要为了更快而篡改代码,而是要找到更好的算法"。

对于非常简单的时间临界循环,可能值得关注事实。编写循环的方式很重要。这里有一些在字符串中进行大规模迭代搜索的基准测试:

  • 传统迭代器方法每次检查.end(): 14秒
  • 在变量中循环开始时缓存.end(): 10秒,提高30% !
  • 使用计数器索引,每次检查.size(): 860 ms
  • 从结束开始计数到0:670 ms,提高22% !
  • 使用指向c_str()的指针,将整个事情减少到…63毫秒!

但是请记住,最好的优化器是你的编译器。在开启优化后,时间分别为1274 ms, 6777 ms, 42 ms, 42 ms和33ms,即从50%到92%的提高!