多层循环嵌套结构的设计

在很多编程的书籍中会给出这样的建议:

在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数。

这个“跨循环层”的概念本身是说,由外层循环进入内层循环是要重新初始化循环计数器的,包括保存外层循环的计数器和加载内层循环计数器,退出内层的时候再恢复外层循环计数器。把长循环放在里面可以显著减小这些操作的数量。看下面两个循环结构:

>>> 结构1

for(i=0; i < 100; i++)

for(j = 0; j < 20; j++)

sum += a[i][j];

>>> 结构2

for(j=0; j < 20; j++)

for(i=0; i < 100; i++)

sum+= a[i][j];

对于结构1来说,当CPU执行到内层循环的时候会执行sum += a[i][j]20次之后跳到外层循环去判断一次,一共需要跳出去100次;对于结构2来说,当CPU执行到内层循环的时候会执行sum += a[i][j]100次才跳到外层,一共需要跳出去20次。很明显对于结构1来说跳出的次数明显大于结构2需要跳出的次数。这就是对于上面这个建议的理解。

但是,这种情况只是在这个二维数组比较小的时候是有效的。另一方面还要注意数据结构本身的效率。这里涉及到数据的Cache命中的概念。如果你的“跳读”会跨越cache交换块,甚至page边界的话,就会造成CPU数据cache重新批量装载数据,甚至从虚拟内存中恢复磁盘数据,这当然严重影响效率。

数组分配之后在内存中是线性存放的,是一整块连续的空间,如果数组的规模大到一定的程度,这个时候操作系统的cache在这个巨大的数组面前显得比较微小的时候就应该从另一个角度去考虑调高效率,计算机中的cache是用来解决主存(也就是通常所说的内存)和CPU之间速率差异的机制,一般为SRAM,速度比主存快,造价比较高。一般情况下操作系统都有一些调度算法去预测CPU下一次所要使用的数据,从而提前把主存中的一部分数据取到cache中,当下次CPU要取的数据就在cache中的话就直接从cache中得到,提高系统效率,具体的cache置换算法请参考网络。所以再看下面两个例子:

>>> 结构3

for(i=0; i < 1000; i++)

for(j=0; j < 500; j++)

for(k=0; k < 100; k++)

sum += a[i][j][k];

>>> 结构4

for(k=0; k < 100; k++)

for(j=0; j < 500; j++)

for(i=0; i < 1000; i++)

sum += a[i][j][k];

从切换层数上计算的话,结构4好像要比结构3好很多,但是如果考虑上CPU置换cache所消耗的时间的话结构3要好于结构4,因为按照结构3的访问顺序,i是最不常变化的,j次之,k是最容易变化的,然而k和k+1在实际的内存中就是挨着的这大大增加了cache命中的机会;然而结构4中,i是最常变化的,而且i变化之后,i+1和i(k和j保持不变)的单元相差了500*100*sizeof(数据类型)个字节,这使得cache命中率下降,因此需要做很多cache的置换工作,这部分时间如果加上的话,结构3比结构4就要好很多。

时间: 2024-10-08 09:29:59

多层循环嵌套结构的设计的相关文章

java的break,另一种用法(多层循环嵌套)

break的另一种用法: 1.跳出外循环 outer:for(int j=0;i<4;j++){//outer随便定义的一个标签 for(int i=0;i<10;i++){ if(i==6) break outer; System.out.println("i="+i); } System.out.println("j="+j); } 2.跳出内循环 for(int j=0;i<4;j++){ inner:for(int i=0;i<10;

第6章第2讲循环嵌套结构

main() { int i,j; for(i=1;i<=4;i++) { for(j=1;j<=i;j++) printf("*"); printf("\n"); } }

C#用链式方法表达循环嵌套

一.起源 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中单,上单,ADC,辅助:第二局新加入的伙伴要选上单,四人可选位置变为:中单,打野,ADC,辅助:要求,第二局四人每人不得选择和第一局相同的位置,请问两局综合考虑有多少种位置选择方式? 对于像我这边不懂游戏的人来讲,看不懂.于是有了这个版本: 有4个人,4只椅子,第一局每人坐一只椅子,第二局去掉第2只椅子,增加第5只椅子,每人坐一只椅子,而且每个人不能与第一局坐相同的椅子.问两局综合考虑,共有多少种可能的情况? 我

Python 三级菜单与优化(一层循环嵌套)

优化的思路是使用单层循环嵌套完成三级菜单,这个优化思路我非常喜欢,我喜欢在编程的时候用最少的东西写出同样的效果,通常这样会绕来绕去,但非常有趣!!! 需求: 1.运行程序输出第一级菜单: 2.选择一级菜单某项,输出二级菜单,同理输出三级菜单: 3.让用户选择是否要退出: 4.有返回上一级菜单的功能: 多层循环嵌套: data = { 'A':{ "Aa":['Aa1','Aa2','Aa3'], "Ab":['Ab1','Ab2','Ab3'], "Ac&

1.10 print triger(for循环嵌套 &amp;&amp; print 输出格式)

for循环嵌套 1.多层循环嵌套首先考虑内层循环,再考虑外层循环 2.循环考虑边界值控制 3.range(初始值,结束值,步长),序列的最后一个值,= 结束值 - 1 print输出格式 1.python2 中print与逗号结合使用:print输出不换行在语句后面加逗号 例:print "*", 2.python2中控制换行 :print实现换行功能就什么也不输入 例:print ""

关于多层循环顺序问题

当遇到多层循环,结构顺序颠倒,这时候可以不用在意顺序,只是说赋值的时候,后面的数先有,但是不会漏掉前面的数字. lostSave.forEach((outlostItem,_v1)=>{ outlostItem.forEach((intlostItem,_v2)=>{ intlostItem.forEach((thrlostItem,_v3)=>{ saveDrawList[_v2].list[_v1].ballList[_v3].lost=thrlostItem; }) }) }) 原

JS中的循环结构、循环嵌套以及函数介绍

[循环结构的步骤]    *①声明循环变量    *②判断循环条件    *③执行循环体(while的{}中的所有代码)操作     *④更新循环变量    *     * 然后,循环执行②③④    *     *     * [JS中循环条件支持的数据类型]    * ①boolean:true 真     false   假    * ②string: 非空字符串为真       空字符串为假    * ③null/NaN/undefined:  全为假    * ④object:全为真 

4循环嵌套和方法

1 循环嵌套 循环嵌套(多重循环):一个循环结构中的循环体包含其他的循环结构. 任意两种循环结构都可以相互嵌套. for(表达式1;表达式2;表达式3){ for(表达式1;表达式2;表达式3){ } } 特点:外层循环执行1次,内层循环有可能执行多次. 只有当内层循环执行结束后,才会执行下次的外层循环. 示例1:打印3行8列的矩形矩形 public class TestLoop{ public static void main(String[] args){ //外层循环控制行数 for(in

JAVA_SE基础——15.循环嵌套

嵌套循环是指在一个循环语句的循环体中再定义一个循环语句结构,while,do-while,for循环语句都可以进行嵌套,并且可以互相嵌套,下面来看下for循环中嵌套for循环的例子. 如下: public class Circulation { public static void main(String[] args) { int i, j; // 定义两个循环变量 for (i = 1; i <= 9; i++) { // 外层循环 for (j = 1; j <= i; j++) { /