考虑以下两个循环,其中N = 10 ^ 9或足够大的东西,以注意到效率低下。
Loop x = 1 to N
total += A(x)
total += B(x)
或
Loop x = 1 to N
total += A(x)
Loop x=1 to N
total += B(x)
当每个函数取x时,执行一些任意的算术运算(例如x ^ 2和3x ^ 3或其他东西,无关紧要),并返回一个值。
整体运行时间是否会有任何差异?如果不是这样的话,何时会出现这种情况?
答案 0 :(得分:2)
每个循环需要四个动作:
当你有一个循环时,你只需要为第1,2和4项“支付”一次;当你有两个循环时,你只需要“支付”两次。
假设调用这两个函数的顺序并不重要,那么在大多数常见情况下差异不会很明显。但是,在非常紧凑的循环非常罕见的情况下,单个循环将占用较少的CPU资源。实际上,loop unwinding的一种常见技术依赖于在循环期间通过多次重复主体来减少每次迭代检查和设置操作在总体CPU负载中的份额,并通过相应的因子减少迭代次数
答案 1 :(得分:2)
有几点需要考虑。一个是你在第二个版本中为循环本身做了两倍的指令(条件检查,递增x
等)。如果你的功能真的微不足道,那可能是一笔不小的费用。
然而,在更现实的情况下,缓存性能,寄存器共享以及类似的东西将产生更大的差异。例如,如果两个函数都需要使用大量寄存器,您可能会发现第二个版本的性能比第一个要差,因为编译器需要将更多寄存器溢出到内存中,因为它每个循环执行一次。或者,如果A
和B
都访问相同的内存,则第二个版本可能比第二个版本更快,因为所有B
的访问都将是第二个版本中的缓存命中但是未命中第一个版本。
所有这些都是高度针对程序和平台的。如果您想要优化某些特定程序,则需要对其进行基准测试。
答案 2 :(得分:1)
主要区别在于第一个测试X对N,N次,而第二个测试X对N,2N次。
答案 3 :(得分:0)
循环本身有轻微的开销。
在每次迭代中,您需要至少执行2次操作,增加计数器,然后将其与结束值进行比较。
所以你要做2 * 10 ^ 9次操作。
答案 4 :(得分:0)
如果两个函数都使用了很多内存,例如它们创建了一些大数组,并在每次迭代中递归修改它,那么由于内存缓存等原因,第一个循环可能会变慢。
答案 5 :(得分:0)
有许多潜在因素需要考虑;
1)迭代次数 - 循环设置是否优先于任务 2)循环比较惩罚与任务复杂性
for (i=0;i<2;i++) a[i]=b[i];
3)功能的一般复杂性
- 有两个复杂的函数,可能会用完寄存器
4)注册依赖项或本质上是任务序列 - 混合的两个独立任务与其他循环的结果取决于第一个
5)循环可以在预取队列上完全执行 - 不需要缓存访问 - 混合第二个任务可能会破坏吞吐量
6)有哪种缓存命中模式