我刚刚从同事那里听说,直接在验证中使用 length 属性,其性能低于将值分配给变量:
for(var i:int=0;i<array.length;i++)
trace(String(i));
for(var i:int=array.length-1;i>-1;i--)
trace(String(i));
他们实际上声称,第二个循环将迭代数组“快 90%”,这是真的吗?
这个问题适用于任何语言,但我只对 AS3 行为感兴趣,尤其是 ArrayCollections。
我刚刚从同事那里听说,直接在验证中使用 length 属性,其性能低于将值分配给变量:
for(var i:int=0;i<array.length;i++)
trace(String(i));
for(var i:int=array.length-1;i>-1;i--)
trace(String(i));
他们实际上声称,第二个循环将迭代数组“快 90%”,这是真的吗?
这个问题适用于任何语言,但我只对 AS3 行为感兴趣,尤其是 ArrayCollections。
这个问题的原因比你想象的要有趣得多。
检查以下代码,它包括七个测试:
结果如下:
为什么你认为最后一个比其他的慢得多?这并不是因为 Array 每次都重新计算长度,那会很愚蠢。
读这个:
length 属性:一个非负整数,指定数组中的元素个数。当新元素添加到数组中时,此属性会自动更新。当您为数组元素赋值时(例如,my_array[index] = value),如果 index 是一个数字,并且 index+1 大于 length 属性,则 length 属性会更新为 index+1。
原因在于执行
//Implementation
public function get length():uint
public function set length(value:uint):void
其他六个测试使用类的常规公共成员。Array 使用 getter 和 setter 函数来检索长度值。如果你继续详细的测试,你会发现函数调用花费了宝贵的时间。当您需要更高的性能时,您有时不得不依赖内联代码。几乎每次都是这样。那是因为处理器必须“跳转”到代码中的不同区域、创建新范围和一些其他原因。
如果您检查向量的长度实现,您会发现它只是一个公共成员,与数组(getter 和 setter)函数不同。Getter 和 Setter 具有更好的可扩展性,如果您决定从类继承,它们可以让您的生活更轻松,setter 还可以通过检查值来防止某些错误。在速度方面,没有什么比公共财产更好的了。
package regression
{
import flash.display.Sprite;
import flash.utils.getTimer;
/**
* ...
* @author Arthur Wulf White
*/
public class Check_Loop_Speed_1 extends Sprite
{
//BIG_NUMBER == 100,000,000
public function Check_Loop_Speed_1()
{
var i : int = 0, j : int = 100000000, time : int = 0;
var vector: Vector.<Boolean> = new Vector.<Boolean>(100000000, true),
vect2 : Vector.<Boolean> = new Vector.<Boolean>(100000000),
obj : Object = new TestObject(),
arr : Array = new Array();
arr.length = 100000000;
//test 1
time = getTimer();
for (i = 0; i < 100000000; i++) { }
trace(getTimer() - time);
//test 2
time = getTimer();
for (i = 0; i < j; i++) { }
trace(getTimer() - time);
//test 3
time = getTimer();
for (i = 0; i < vector.length; i++) { }
trace(getTimer() - time);
//test 4
time = getTimer();
for (i = 0; i < vect2.length; i++) { }
trace(getTimer() - time);
//test 5
time = getTimer();
for (i = 0; i < obj.val; i++) { }
trace(getTimer() - time);
//test 6
time = getTimer();
for (i = 0; i < obj.val2; i++) { }
trace(getTimer() - time);
//test 7
time = getTimer();
for (i = 0; i < arr.length; i++) { }
trace(getTimer() - time);
}
}
}
class TestObject
{
public var val : uint = 100000000;
public const val2 : uint = 100000000;
}
你的朋友是正确的,但 90% 不会是一致的。
一种测试方法:
import flash.utils.getTimer;
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0);
btn.graphics.drawRect(0,0,100,50);
btn.addEventListener(MouseEvent.CLICK,test);
addChild(btn);
var array:Array = new Array();
var arraySize:int = 100000;
for(var i:int=0;i < arraySize;i++){
array.push(i);
}
function test(e:Event):void {
var i:int = 0; //initialize before getTimer so all things are equal
var curTime:Number = 0;
curTimer = getTimer();
for(i=0;i<array.length;i++){
doSomething(i);
}
trace("First Took: ", (getTimer() - curTime) + "ms");
curTime = getTimer();
for(i=array.length-1;i>-1;i--){
doSomething(i);
}
trace("Second Took: ", (getTimer() - curTime) + "ms");
};
function doSomething(index:int):void {
index = index * 2; //some arbitrary function - don't trace!!!
}