【问题标题】:Is looping faster than traversing one by one循环比一一遍历快
【发布时间】:2017-02-20 23:06:32
【问题描述】:

让我们考虑下面的 C++ 代码 sn-p 打印第一个 10 个正整数:

for (int i = 1; i<11;i++)

{

  cout<< i ;

}

这会比依次打印每个整数快还是慢,如下所示:

x =1;

cout<< x;

x++;

cout<< x;

等等..

有什么理由说明为什么它应该更快或更慢?它会因一种语言而异吗?

【问题讨论】:

  • 比较操作次数。一样的。
  • 为什么循环应该更快?是的。缓存。
  • @lukai 我不认为操作的数量是相同的:在非循环版本中没有发生比较。 (虽然这种方法在现实生活中几乎没用)
  • 它是 I/O 绑定的。您不会注意到,甚至可能不会测量计算时间差。
  • 请注意,第二种方法违反了 DRY 原则(en.wikipedia.org/wiki/Don't_repeat_yourself),会使程序难以维护。再加上编译器已经足够聪明,可以在编译时“在幕后”执行相同的技巧,如果它可能有用,那么真的没有理由手动执行。

标签: c++ performance loops


【解决方案1】:

这个问题类似于this one;我在下面复制了my answer to that question 的摘录...(数字不同;11 与 50;分析相同)

您正在考虑使用手动形式的循环展开。循环展开是编译器有时用于减少循环中涉及的开销的优化。只有在编译时可以知道循环的迭代次数(即迭代次数是常数,即使该常数涉及基于其他常数的计算),编译器才能做到这一点。在某些情况下,编译器可能会确定值得展开循环,但通常不会完全展开循环。例如,在您的示例中,编译器可能会确定将循环从 50 次迭代展开到仅具有 5 个循环体副本的 10 次迭代将具有速度优势。循环变量仍然存在,但不是对循环计数器进行 50 次比较,现在代码只需进行 10 次比较。这是一个折衷方案,因为循环体的 5 个副本在缓存中占用了 5 倍的空间,这意味着加载相同指令的这些额外副本会强制缓存驱逐(丢弃)已经存在的许多指令缓存并且您可能希望保留在缓存中。此外,从主内存加载这 4 个额外的循环体指令副本比在根本没有展开循环的情况下简单地从缓存中抓取已经加载的指令要花费更多时间。

总而言之,只使用循环体的一份副本并继续保留循环逻辑通常更有利。 (即根本不进行任何循环展开。)

【讨论】:

    【解决方案2】:

    在循环中,实际的机器级指令将是相同的,因此是相同的地址。在显式语句中,指令将具有不同的地址。因此,对于 for 循环,CPU 的指令缓存可能会提供后一种情况可能不会发生的性能提升。

    对于非常小的范围 (10),差异很可能可以忽略不计。对于相当长的循环,它可以更清晰地显示出来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-29
      • 2014-01-23
      • 1970-01-01
      • 1970-01-01
      • 2015-10-14
      • 2017-05-21
      • 2021-12-09
      • 2013-11-06
      相关资源
      最近更新 更多