注意:
经过Aone的提醒发现一个问题,如果为了代码的可读性而将process()封装为函数,反而会导致增加了一次函数调用的指针跳转,拖慢了程序得不偿失。因此只推荐在需要极限优化超过代码可读性的情况下使用。
Duff's Device算法是一个老东西了,最早是在1983年C上由Tom Duff实现,然后2001年Jeff Greenberg移植到JavaScript上。算是很久的一个优化方案了 -_-b...竟然到现在才被发现。
话不多少,绕回正题,在遍历数组时众所周知的方法就是使用标准的for循环
var array:Array;//假设已有数据
标准方法:
复制代码
一个基本的结构下来,除开process函数的代码质量不说,最大的开销放在 i < length 的Boolen比较之上,Duff's Device算法的目的即在于减少迭代的次数从而获得代码效率的提升。
Duff's Device实现一:
复制代码
Duff's Device的基本理念是:在每次while循环中调用8次process函数,当然由于不是每个array都能被8整除,所以通过变量startAt记录下多出的余数,并通过switch在第一次循环时process多出来的部分。
通过这种巧妙的写法,迭代的次数被减少到了1/8左右。有人问那为什么是8,这里没有认真考究,但据说是跟内存的分配为8的倍数有关,每一次迭代进行8次process,有较大的可能分配到内存条相邻的的区间,从而提高跟寄存器的读取命中策略(Tom Duff当初貌似就是从汇编里取得灵感才写出最早那段C的代码),从而达到提高效率的目的。
Duff's Device优化实现(忘了经典实现吧,这个更好):
复制代码
这里将非8的余数的部分单独抽离出来,减少了switch的判断,从而比经典循环更快。
效果:
在AS上做了测试,在100万次for,process函数为单步运算时,普通的for循环耗时40ms左右,优化版本的Duff's Device运行时间仅为4ms。可以预见在粒子 动画和做 游戏时遍历对象时和碰撞检测时应该会有很棒的效率提升。
当然不得不吐槽的是这种底层的优化不应该由这种“奇技淫巧”来实现,毕竟这样影响了代码的可读性。这部分的优化更应该在将for循环转化为机器码时做好处理。
经过Aone的提醒发现一个问题,如果为了代码的可读性而将process()封装为函数,反而会导致增加了一次函数调用的指针跳转,拖慢了程序得不偿失。因此只推荐在需要极限优化超过代码可读性的情况下使用。
Duff's Device算法是一个老东西了,最早是在1983年C上由Tom Duff实现,然后2001年Jeff Greenberg移植到JavaScript上。算是很久的一个优化方案了 -_-b...竟然到现在才被发现。
话不多少,绕回正题,在遍历数组时众所周知的方法就是使用标准的for循环
var array:Array;//假设已有数据
标准方法:
- var length:int = array.length;
- for(var i:int = 0; i < length; i++) {
- process(array[i] as xxx);
- }
Duff's Device实现一:
- var iterations:int = Math.floor(array.length / 8);
- var startAt:int = array.length % 8;
- var i:int = 0;
- do {
- swtich (startAt) {
- case 0: process(array[i++]);
- case 7: process(array[i++]);
- case 6: process(array[i++]);
- case 5: process(array[i++]);
- case 4: process(array[i++]);
- case 3: process(array[i++]);
- case 2: process(array[i++]);
- case 1: process(array[i++]);
- }
- startAt = 0;
- } while(--iterations);
通过这种巧妙的写法,迭代的次数被减少到了1/8左右。有人问那为什么是8,这里没有认真考究,但据说是跟内存的分配为8的倍数有关,每一次迭代进行8次process,有较大的可能分配到内存条相邻的的区间,从而提高跟寄存器的读取命中策略(Tom Duff当初貌似就是从汇编里取得灵感才写出最早那段C的代码),从而达到提高效率的目的。
Duff's Device优化实现(忘了经典实现吧,这个更好):
- var i:int = items.length % 8;
- while(i) {
- process(array[i--]);
- }
- i = Math.floor(array.length);
- while(i) {
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- process(array[i--]);
- }
效果:
在AS上做了测试,在100万次for,process函数为单步运算时,普通的for循环耗时40ms左右,优化版本的Duff's Device运行时间仅为4ms。可以预见在粒子 动画和做 游戏时遍历对象时和碰撞检测时应该会有很棒的效率提升。
当然不得不吐槽的是这种底层的优化不应该由这种“奇技淫巧”来实现,毕竟这样影响了代码的可读性。这部分的优化更应该在将for循环转化为机器码时做好处理。