AS3用于验证循环性能差异

时间:2012-09-28 00:09:41

标签: actionscript-3

我刚刚从同事那里听说,在验证中直接使用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上。

2 个答案:

答案 0 :(得分:2)

这个问题的原因比你想象的要有趣得多。

检查以下代码,它包括七个测试:

结果如下:

  1. 864 - 与文字常量int
  2. 比较
  3. 866 - 与int比较
  4. 1358 - 与矢量长度(固定大小)进行比较
  5. 1376 - 使用矢量长度(动态大小)
  6. 3159 - 与对象成员比较
  7. 3152 - 与静态对象成员比较
  8. 11855 - 与数组长度进行比较
  9. 为什么你认为最后一个与其他人相比非常慢? 这不是因为数组每次重新计算长度,这将是愚蠢的。

    阅读本文:

      

    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
    

    其他六个测试使用一个普通的公共成员。 数组使用getter和setter函数来检索长度值。 如果您继续详细说明测试,您将看到功能调用需要花费宝贵的时间。 当您需要更高的性能时,有时您必须依赖内联代码。 这几乎每次都是如此。那是因为处理器必须“跳跃”。到代码中的不同区域,创建一个新的范围和一些其他原因。

    Why is inlining considered faster than a function call?

    如果你检查vector的长度实现,你会发现它只是一个公共成员,不像array(getter和setter)函数。 Getters和Setter更适合于可扩展性,如果您决定从类继承,它们可以使您的生活更轻松,setters也可以通过检查值来防止某些错误。没有什么比公共财产更快的了。

    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;
    }
    

答案 1 :(得分:1)

你的朋友是对的,但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!!!
}