《代码优化:有效使用内存》读书笔记(二)——优化技巧之展开循环

从本节开始,我将与大家分享本书中介绍的内存优化操作方法,集中讨论大型内存块的优化与内存密集型流处理算法。
在很多程序中,密集内存访问是不可避免的,以我经常做的图像处理程序为例,我们会经常性地遍历图片,也就是频繁密集地访问内存,而不管存储器吞吐量的增长多么可观,以及存取时间是如何急剧下降,RAM总是限制系统总体性能的瓶颈之一。一般数据处理算法很少用到RAM性能的三分之一,算法的性能常远远低于这个水平,不幸的是,很少有程序员会关心这个问题。阅读本节之后大家会了解到,经过适当组织的数据交换过程通常会快很多。
这里给出的算法和优化技术是与硬件无关的,并且可以在大多数平台和操作系统上实现。
以上是关于内存优化操作方法的一个综述,言归正传,下面我要讲如何用展开循环的方式来实现优化。
优化原理:
流水线型微处理器对分支语句表现出过度的敏感,从而极大地降低了程序执行程度(循环是一种分值类型)。打个比方,处理器好比是赛跑选手,而软件代码则是跑道。选手必须在每个转弯的地方(也就是每个分支点)减速。跑道中弯道比较少(而直道比较长)意味着完成比赛所需要的时间也比较少。
优化方法:
现在来看一个例子:
for (a = 0; a < 666; a++)
{
x+=p[a];
}
在处理看来,这个循环充满了弯道、陷坑与障碍物,而没有一点直道。展开该循环会是情况有所好转。为使循环分支的迭代次数降低一倍,应该按一下方式组织这个循环:
for (a = 0; a < 666; a+=2)
{
//注意,循环展开以后,执行步骤增加了。
     x+=p[a];
     x+=p[a+1];
//这是加倍的循环体
//循环计数值进行了调整
}
四重循环甚至会显得更加高效。不过,由于循环迭代次数并不是4的整数倍,因此是不能直接达到这种目的的。解决该问题的一种方法是将迭代次数取为最靠近4的整数倍,并将余下的迭代放在循环体之外完成。
如果迭代次数在编译时刻是未知的,那又该怎么办?在这种情况下,应该明智地使用位运算:
for (a = 0; a < (N&~3); a+=4)
{
// 这给出了在达到表示循环因素的数目之前的近似循环迭代次数。
     x+=p[a];
     x+=p[a+1];
     x+=p[a+2];
     x+=p[a+3];
}
for (a=(N&~3); a < N; a++)
{
x+=p[a];
// 剩下的迭代添加在末尾
}

在上面的代码中,表达式(N&~3)是在得到其值为4的表述之前迭代次数的值。我想大家不禁要问,为什么是4,而不是8、16?鼓舞人心的是,本书的作者做过测试,并将测试结果公布出来,我用手机拍了一下这张图,给大家分享一下, 不是很清晰,将就一下子吧。
《代码优化:有效使用内存》读书笔记(二)鈥斺斢呕记芍箍
可以看出,针对循环的深入展开可以使执行时间减少过半。不过,过于深入的展开反而会降低性能。高速缓存是容纳不下这样一个庞然大物的,因而会降低性能。

该方法看上去非常易于实现,而且对性能提高比较显著,我想大部分同学对这个不会太相信,有兴趣的可以试试。阻碍大家使用这一方法的另一个原因就是,对于代码可读性要求比较高的人来说,这种编码方式,的确会让人感觉很繁琐。
我现在在一些对速度要求比较严格的地方,都采用了这个方法,因为很多时候程序的速度对我来说至关重要,如果有朋友对速度要求也是非常苛刻的话,不妨试试,会有意想不到的收获~
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值