September 11, 2007

【黑羽】AS3教程(13):AS3中的数据存取方式效率比较

ActionScript3天地会公测中...

今天又有一位朋友和我在MSN上聊起了AS3中存取数据效率的话题,突然想起以前曾在blueidea论坛上讨论过。这个话题还有蛮多人感兴趣,比较实用,让它在论坛上沉下去有些可惜。因此特地整理成帖,希望对大家有用。废话少说,看蕉:
使用如下几种存取数据方式进行存取100万次运算,所花时间依次为(单位为毫秒,ms):

如下几种存取数据方式100万次存取运算效率依次为:

* 类定义中的属性(如public、private类属性) 135 毫秒
Point类对象 140 毫秒
Rectangle类对象(x等属性) 140ms
* Array类对象 270ms
* Object类对象 500 ms
动态类动态属性 550
* Rectangle类对象(left等属性) 700
* 自定义类getter/setter 1000
自定义类Function 1000
(以上测试结果是由eidiot测试的,感谢eidiot。稍微做了一点文字修改。见讨论原帖

问题1:为什么会有速度差别?

  最快的是第一类,速度是Array的两倍,Object的四倍,getter/setter的约八倍。存取坐标要用Point和Rectangle,比Array快的多。 Object和动态类效率较低,一般情况下请尽量使用密封类。 

测试用的自定义类是密封类,那么,public等类定义中定义好的属性比Array和Object快是正常的。因为查询密封类的类成员(包括属性和方法)只需要查询TraitObj,加一个 prototype obj。而Array, Object都是动态类,不论是内存分配和name lookup都需要额外的开销。
同理,Point、Rectangle也是密封类,当然比Array和Object要快。
这是AS3新的内部实现机制的优点。如果在AS2.0中,则不会有差别。注,AS2的密封类和动态类的支持只存在于编译阶段,在运行时没有区别,无法区分。
有兴趣的朋友可以试试将AS3自定义类设成动态类,再使用动态属性和非动态属性存取10万次比较看看。

问题2:为什么有些类的属性效率会存在差异?比如Rectangle的x属性和left属性为何差别这么大?

Rectangle类除了x,y,width,height,其余属性全部是getter和setter,不是真正的属性。使用getter和setter时,函数调用需要一些开销,自然比真正的属性要慢一些。

问题3:为何动态类和密封类的类定义中的成员效率没有差别?

这个是正常的。并不费解。之前想问有没有区分动态成员和非动态成员,就是要弄清这个问题。

只要是我们在类定义中定义的成员(包括属性和方法),都在这个类对应的Trait obj中。动态类和密封类都一样。因此,密封类和动态类的属性,方法效率都会相同。具体的实现是通过Slot方式来实现,通过slot index来访问,效率高。

问题4:动态成员的效率和非动态成员的效率为何有差距?AS2中为何没有这样的区别?

因为动态类的动态属性不存在与trait obj中,而是在prototype obj中一个类似于哈希表的数据结构中。哈希表代价是name lookup效率明显低于slot方式,而且生成时系统的开销较大。因此AS3中,动态类的动态成员效率低于类定义中定义的成员。 在AS2中,动态属性和非动态属性的区别只存在于编译阶段,运行时并没有区别。因为运行时,实质上所有对象成员都是以name为索引,name都存储在一张hash table(哈希表)中。所以AS2中没有AS3效率高,也没有这些区别。

问题5:private成员和public成员效率有没有差别?

访问private成员和访问public成员不会更快。实际上public, private, protected, internal等只是AS3中内嵌的四个命名空间而已,并不会对访问速度产生差异。他们在Trait obj中都是同样使用slot来存储的,访问也都是通过slot index。 理论上说,我们使用自定义的命名空间来修饰类成员,那么这个类成员的访问速度也应该和内嵌的命名空间一样。有兄弟感兴趣的话,可以继续试试使用自定义命名空间来测试一下。

有趣的发现:看测试结果,似乎Rectangle实现的getter和setter速度,要比一般的getter和sette和自定义function要快300。这个真是很有趣。

解释:AS3中不少核心类的方法都是native(关键字)实现,即最终的实现是由AVM语言自然代码(native code)实现,而不是ActionScript代码实现。比如Object类,Class类等等,他们的方法都是native的,由相应的C++代码实现。因此,会比我们自定义类的效率要高不少。

黑羽可以肯定的是,核心类中的实现都是native code。但是,Rectangle类的功能并不复杂,而且处于flash.geom包,非核心类。我在想,难道连这个类的方法也是native实现吗?
如果测试多次也是这样,并且测试方法无偏差,那么基本上可以肯定Rectangle类中也是使用了native code。
那么做一个推论,是否只要是Flash API的类基本上都是由native code实现呢?
建议使用其他包中的类,也测试一下他们的getter和setter。如果Flash API中类的getter和setter速度一致,且比自定义类的快,那么大概可以下结论,所有Flash Player API(包括核心类和非核心类)真的都是用native code实现的。

广告:哈哈,现在刚好是阿里妈妈推广期哦,你是站长吗?推荐注册阿里妈妈赚广告费

TrackBack

TrackBack URL for this entry:
http://www.kingda.org/mt/mt-tb.cgi/206

Comments (10)

那静态和非静态的属性,哪个更快点

领教领教!!
谢谢...

morning:

请问下这是一个类存取100万次一共话的时间吗?
应该和CPU的运算速度有关是吧?

to morning:
不是类存取,而是类生成的对象存取。:)
与测试电脑有关?是的,运算时间当然和测试环境有关。不过这儿主要关心的是相对的速度,即谁比谁快,快多少,所以测试环境没有关系。大家都可以用自己电脑测一测。

to songhuan:
静态属性保存在Class Traits Obj中,理论上说存储效率应当和Traits obj差不多。但实际上,在读取Class Traits Obj要产生一些额外的消耗,它的读取效率比实例属性要低,比实例getter setter要高。
在我电脑测试,实例属性100万次消耗9毫秒,静态属性190ms左右,实例getter和setter大约400毫秒左右。

Merrycat:

请教个问题,用Eclipse+FDT开发AS2.0程序时,有些在Flash IDE中正常的语法语句在Eclipse+FDT中却会提示错误,如以下这种情况错误多见:

private function result(event:Object) : Void {
trace(event.target.results);
}


提示:Variable "target" is not declared

如此情况应该怎样解决呢?

to MerryCat:
下次不要回帖问与本帖无关的问题...
你可以用自定义事件类的方法解决这个AS2问题,参见下面链接中最后一段:
EventSender工具类

Merrycat:

实在抱歉,实在是在首页上没找到留言的版块和相关的文章,只好发到评论里来了。

to merrycat:
哦,这也是。
我尽快开通一个供大家专门问问题的地方。

ioi:

黑羽大哥,你的书上市了么?我在上海博库书城都没看到有卖啊。可以网上买么?哪里可以买到。你在BLOG里面写的这些在书里面都有么

黑羽师傅,(1)AS3.0在没有构造函数时也自动生成呀?
(2)“将 FLA 文件中Document 类设置为 ButtonExample” 如何操作呀?
(3)可不可以将第一帧上的代码理解为执行类的入口函数呀?

留下高见,发表评论

个人信息不会外泄,请放心填写。

姓名和Email必填。

发表评论后,请耐心等待,不要频繁刷新。提交完成后,刷新一下本页即可看到您的评论。^_^

请输入验证字符"o" :
文字广告:你是站长吗?注册阿里妈妈赚广告费

最近发表

归档

全部
Creative Commons License
此 Blog 中的日记
遵循以下授权:
Creative Commons
(创作共用) 授权
.