1

同僚から、検証で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));

彼らは実際に、2番目のループが「最大90%高速」に配列を反復処理すると主張していますが、これは本当ですか?

この質問はどの言語にも当てはまりますが、特にArrayCollectionsでのAS3の動​​作にのみ関心があります。

4

2 に答える 2

2

この問題の理由は、予想よりもはるかに興味深いものです。

次のコードを調べてください。7つのテストが含まれています。

結果は次のとおりです。

  1. 864-リテラル定数intと比較
  2. 866-intと比較
  3. 1358-ベクトルの長さと比較(サイズは固定)
  4. 1376-ベクトルの長さで計算(動的サイズ)
  5. 3159-オブジェクトメンバーと比較
  6. 3152-静的オブジェクトメンバーと比較
  7. 11855-配列の長さと比較

なぜ最後のものは他のものと比較してとても遅いと思いますか?配列が毎回長さを再計算するからではなく、それはばかげているでしょう。

これを読む:

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

他の6つのテストでは、クラスの通常のパブリックメンバーを使用します。配列はgetter関数と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;
}
于 2012-09-28T09:37:52.450 に答える
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!!!
}
于 2012-09-28T00:15:59.590 に答える