小循环中的大循环总是比大循环中的小循环快吗
Is a big loop within a small loop always faster than a small loop within a big one?
我刚刚读了这篇文章,想知道我们是否可以得出这样的结论:无论代码在嵌套循环中做什么,小循环中的大循环总是比大循环中的小循环运行得更快?举个例子。
int m, n;
m = 1000000;
n = 10;
代码段A
for (int i = 0; i < n; i++)
for (int j=0; j < m; j++)
{
DoSomething();
}
代码段B
for (int j = 0; j < m; j++)
for (int i=0; i < n; i++)
{
DoSomething();
}
我们可以说,无论DoSomething((实际做什么,片段A总是比片段B运行得更快吗?
正如@stackmate所指出的,我想将这个问题扩展为两个
当嵌套循环中的代码是DoSomething((时,这意味着DoSomething((与变量i和j无关性能差异?
当嵌套循环中的代码是DoSomething(i,j(时,这意味着DoSomething(i,j(与变量i和j有相关性。性能差异是什么?
您的问题不能有一个具体的答案。决定它是否快的参数是你在循环中所做的。例如,假设您正在添加2个数组,并将它们存储在第三个数组中:
Code 1:
for(int i = 0; i < 1000; i++)
{
for(int j = 0; j < 1000000; j++)
C[i][j] = A[i][j] + B[i][j];
}
Code 2:
for(int i = 0; i < 1000000; i++)
{
for(int j = 0; j < 1000; j++)
C[j][i] = A[j][i] + B[j][i];
}
代码1将比代码2快得多。原因是缓存。查看此问题以了解更多详细信息。这些答案信息丰富,我在这里再次解释缓存的概念毫无意义。
@Cool_Code已经涵盖了一个主要原因(内存访问模式导致更好的缓存命中率(,即为什么将较小的循环作为内部循环是有益的。
另一种情况是可以展开内部循环。特别是如果较小循环的大小真的很小并且是固定的,编译器将展开内部循环(如果有益的话(。生成的代码将只有一个循环,而不是两个嵌套的循环,并减少分支。
如果在高性能关键代码中遇到这样的情况,则需要同时尝试这两种方法,并仔细进行基准测试。如果代码不是非常关键的性能,那么可能不值得担心。
一个观察。如果您在嵌套循环中读取操作,如以下
for (int i = 0; i < n; i++)
a = aList.get(i);
for (int j=0; j < m; j++)
{
b = bList.get(j)
DoSomething(a, b);
}
则具有CCD_ 1导致比CCD_ 3更少的CCD_。对于n=1
和m=2
将有三个读取操作,而对于n=2
和m=1
将有四个读取操作。在n > m
的情况下,将有更多的重复读取操作。或者换句话说,运行时是n + n*m
。无论是CCD_ 11还是CCD_ 12,值CCD_。
(我假设没有编译器优化并忽略缓存行为(
这取决于情况。
如果在for循环之间做任何其他事情,那么首先迭代m的循环将需要更长的时间来执行,这只是因为它在进入下一个循环之前做了更多的工作,因为额外增加了工作。
如果没有,则
n * m = m * n
T的评论也是正确的。当外部循环是最长的一个时,内部循环的初始化会更频繁。如果这是c++,我希望编译器对此进行优化,以便对代码进行基准测试可能会为两个循环产生相同的结果。
在代码段A:n < m
3次切换到外部For循环但在代码段B:m=1000000
次切换到外部For循环。这个原因(在两个For循环之间切换更多(使代码段A比代码段B更快。
for(int i = 0; i < 1000; i++)
{
for(int j = 0;
在上面的代码中,如果您看到我们正在初始化j 1000次。
for(int i = 0; i < 1000000; i++)
{
for(int j = 0;
而在第二个代码中,我们初始化了j1000000次,这清楚地表明第二个码有额外的开销。
我认为这里正在进行大量优化。查看此jsben.ch:https://jsben.ch/FjXuL
var big = 10000;
var little = 10;
var x = 0;
// Little loop in Big loop
for (var i = 0; i < big; i++) for (var j=0; j < little; j++) { x++; }
// Big loop in Little loop
for (var i = 0; i < little; i++) for (var j=0; j < big; j++) { x++; }
// Little loop in Big loop (single initializations)
var j;
for (var i = 0; i < big; i++) for (j=0; j < little; j++) { x++; }
// Big loop in Little loop (single initializations)
var j;
for (var i = 0; i < little; i++) for (j=0; j < big; j++) { x++; }
当单独测试时,大循环中的小循环在Chrome中总是领先。在"循环"中的第一个循环之外声明j;"单一初始化";测试似乎没有帮助,而且实际上大大降低了大循环中的小循环(单个初始化(测试的速度。
也就是说,结果可能因浏览器实现/编译器而异。
我认为嵌套较大的循环是有利的,这是合乎逻辑的,因为初始化嵌套的j变量的次数更少,但显然在Chrome中,这不是性能的一个大因素,因为嵌套较小的循环更快。