多层循环嵌套结构的设计
来源:互联网 发布:zookeeper用了什么算法 编辑:程序博客网 时间:2024/05/22 00:34
在很多编程的书籍中会给出这样的建议:
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少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就要好很多。
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少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就要好很多。
0 0
- 多层循环嵌套结构的设计
- C# foreach多层循环嵌套的退出
- 如何跳出嵌套多层的循环
- 微信小程序的多层循环嵌套
- 枚举多层循环嵌套
- angularjs2 如何嵌套多层循环
- 试嵌套多层For循环的性能和优化方案
- jsp中数据库的多层while循环嵌套查…
- 列表渲染多层嵌套循环及wx:key的使用
- 有关vue v-for 多层循环嵌套获取 行数的
- 2.9 循环结构-循环的嵌套
- lua下打印有多层嵌套的table结构
- B/S结构的多层系统设计
- OC 跳出多层for循环嵌套 goto
- 59 C语言循环结构的嵌套
- h5循环结构,嵌套
- C/C++中的多层嵌套结构
- 多层的if循环
- linux 网线是否插入
- android基础内容介绍(XXXDrawable、Android动画、Android资源使用、Fragment与Activity)
- iOS百度地图SDK2.4.1版本的使用(一)
- HDOJ 题目2085核反应堆(递推)
- 【OC学习-20】NSSet集合对象初始化以及常用操作方法归纳
- 多层循环嵌套结构的设计
- win7防火墙无法启动的代码修复
- 诗歌rails 之extend的用法
- Python 代码性能优化技巧
- ubuntu 执行 shell
- MySQL常用函数
- 第三章 F# 和 C# 中元组、列表和函数
- ERROR namenode.NameNode: java.io.IOException: Cannot create directory /export/home/dfs/name/current
- HDOJ 题目1995汉诺塔V(递推)