[转] 使用Duff's Device算法优化for循环

注意:
经过Aone的提醒发现一个问题,如果为了代码的可读性而将process()封装为函数,反而会导致增加了一次函数调用的指针跳转,拖慢了程序得不偿失。因此只推荐在需要极限优化超过代码可读性的情况下使用。


Duff's Device算法是一个老东西了,最早是在1983年C上由Tom Duff实现,然后2001年Jeff Greenberg移植到JavaScript上。算是很久的一个优化方案了 -_-b...竟然到现在才被发现。

话不多少,绕回正题,在遍历数组时众所周知的方法就是使用标准的for循环

var array:Array;//假设已有数据

标准方法:
  1. var length:int = array.length;

  2. for(var i:int = 0; i < length; i++) {

  3.     process(array[i] as xxx);

  4. }
复制代码
一个基本的结构下来,除开process函数的代码质量不说,最大的开销放在 i < length 的Boolen比较之上,Duff's Device算法的目的即在于减少迭代的次数从而获得代码效率的提升。



Duff's Device实现一:
  1. var iterations:int = Math.floor(array.length / 8);

  2. var startAt:int = array.length % 8;

  3. var i:int = 0;

  4. do {

  5.     swtich (startAt) {

  6.         case 0: process(array[i++]);

  7.         case 7: process(array[i++]);

  8.         case 6: process(array[i++]);

  9.         case 5: process(array[i++]);

  10.         case 4: process(array[i++]);

  11.         case 3: process(array[i++]);

  12.         case 2: process(array[i++]);

  13.         case 1: process(array[i++]);

  14.      }

  15.     startAt = 0;

  16. } while(--iterations);
复制代码
Duff's Device的基本理念是:在每次while循环中调用8次process函数,当然由于不是每个array都能被8整除,所以通过变量startAt记录下多出的余数,并通过switch在第一次循环时process多出来的部分。

通过这种巧妙的写法,迭代的次数被减少到了1/8左右。有人问那为什么是8,这里没有认真考究,但据说是跟内存的分配为8的倍数有关,每一次迭代进行8次process,有较大的可能分配到内存条相邻的的区间,从而提高跟寄存器的读取命中策略(Tom Duff当初貌似就是从汇编里取得灵感才写出最早那段C的代码),从而达到提高效率的目的。

Duff's Device优化实现(忘了经典实现吧,这个更好):
  1. var i:int = items.length % 8;

  2. while(i) {

  3.     process(array[i--]);

  4. }

  5. i = Math.floor(array.length);

  6. while(i) {

  7.     process(array[i--]);

  8.     process(array[i--]);

  9.     process(array[i--]);

  10.     process(array[i--]);

  11.     process(array[i--]);

  12.     process(array[i--]);

  13.     process(array[i--]);

  14.     process(array[i--]);

  15. }
复制代码
这里将非8的余数的部分单独抽离出来,减少了switch的判断,从而比经典循环更快。

效果

在AS上做了测试,在100万次for,process函数为单步运算时,普通的for循环耗时40ms左右,优化版本的Duff's Device运行时间仅为4ms。可以预见在粒子 动画和做 游戏时遍历对象时和碰撞检测时应该会有很棒的效率提升。

当然不得不吐槽的是这种底层的优化不应该由这种“奇技淫巧”来实现,毕竟这样影响了代码的可读性。这部分的优化更应该在将for循环转化为机器码时做好处理。

转载于:https://www.cnblogs.com/appleseed/archive/2011/02/14/1954095.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值