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

来源:互联网 发布:一淘网是淘宝的吗 编辑:程序博客网 时间:2024/04/30 23:28

今天又有一位朋友和我在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实现的。