惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
J
Java Code Geeks
雷峰网
雷峰网
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
V
Vulnerabilities – Threatpost
S
Securelist
The Hacker News
The Hacker News
The Register - Security
The Register - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Help Net Security
Help Net Security
G
Google Developers Blog
Hugging Face - Blog
Hugging Face - Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
M
MIT News - Artificial intelligence
AI
AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Schneier on Security
Schneier on Security
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
Google DeepMind News
Google DeepMind News
Hacker News - Newest:
Hacker News - Newest: "LLM"
H
Hacker News: Front Page
博客园 - 司徒正美
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
B
Blog
Microsoft Azure Blog
Microsoft Azure Blog
大猫的无限游戏
大猫的无限游戏
Security Latest
Security Latest
Engineering at Meta
Engineering at Meta
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Threat Research - Cisco Blogs
U
Unit 42
V
V2EX
V2EX - 技术
V2EX - 技术
L
LINUX DO - 最新话题
aimingoo的专栏
aimingoo的专栏
Microsoft Security Blog
Microsoft Security Blog
Recorded Future
Recorded Future
P
Privacy & Cybersecurity Law Blog
美团技术团队
小众软件
小众软件
F
Fortinet All Blogs

博客园 - appleseed

搭建一个typescript下的webgl写代码环境。 Unity3d 小游戏从入门到??? Unity3d 小游戏详解 linux随笔 使用public/private key让putty(ssh)自动登录(以及linux上使用密钥做ssh自动登陆) texturetool 3d专业术语 Molehill 转 降频的时候处理方法 转 [教程] [Lii]最小帧速下的强制渲染——自制图像引擎的同学看过来 - appleseed AI笔记 as3对象池研究 启动GPU加速的方法 恋爱秘籍 .... ..... AS3位运算
[转] 使用Duff's Device算法优化for循环
appleseed · 2011-02-14 · via 博客园 - appleseed

注意:
经过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循环转化为机器码时做好处理。