5

このコードをFlashでテストします。

var i:int = 0;
for (var j:int = 0; j < 5000000; j++)
{
    i=i+1;
}// use about 300ms.

i = 0;
for (var j:int = 0; j < 5000000; j++)
{
    i++;
}// use about 400ms

i = 0;
for (var j:int = 0; j < 5000000; j++)
{
    ++i;
}// use about 400ms too

i=i+1他の人では遅いのに、ActionScript 3で速いのはなぜですか?

申し訳ありませんが、間違いがあります。上記のコードは同時に使用されます。しかし、それを機能させると、結果は異なります。

var i:int;
var j:int;
var startTime:Number;

function func1():void
{
    i = i + 1;
}

function func2():void
{
    i++;
}

startTime = getTimer();
i = 0;
for (j = 0; j < 10000000; j++)
{
    func1();
}
trace(getTimer() - startTime);//5 times:631,628,641,628,632

startTime = getTimer();
i = 0;
for (j = 0; j < 10000000; j++)
{
    func2();
}
trace(getTimer() - startTime);//5 times:800,814,791,832,777
4

5 に答える 5

5

ループが配置されている場所は、パフォーマンスに大きな影響を与える可能性があります。ループが関数内にある場合、Flashはローカルレジスタを使用して計算を実行します。したがって、を含むループi++は次のオペコードを生成します。

000013 inclocal_i (REG_2)  ; increment i 
000015 inclocal_i (REG_3)  ; increment j
000017 getlocal (REG_3)    ; push j onto stack
000018 pushint 5000000     ; push 5000000 onto stack
000020 iflt -12            ; jump backward if less than

を含むループi = i + 1は、次を生成します。

000013 getlocal (REG_2)    ; push i onto stack
000014 pushbyte 1          ; push 1 onto stack
000016 add                 ; add the two
000017 convert_i           ; coerce to integer
000018 setlocal (REG_2)    ; save i back to register 2
000019 inclocal_i (REG_3)  
000021 getlocal (REG_3)
000022 pushint 5000000
000024 iflt -16

i++i = i + 1inclocal_iは、レジスタをスタックにロードして保存し直すことなく、レジスタを直接変更するため、ここよりも高速です。

フレームスクリプト内に配置すると、ループの効率が大幅に低下します。Flashは、宣言された変数をクラス変数として格納します。それらにアクセスするには、より多くの作業が必要です。i++ループの結果は次のようになります。

000017 getlocal (REG_0, this)   ; push this onto stack
000018 dup                      ; duplicate it
000019 setlocal (REG_2)         ; save this to register 2
000020 getproperty i            ; get property "i"
000022 increment_i              ; add one to it
000023 setlocal (REG_3)         ; save result to register 3
000024 getlocal (REG_2)         ; get this from register 2
000025 getlocal (REG_3)         ; get value from register 3
000026 setproperty i            ; set property "i"
000028 kill (REG_3)             ; kill register 2
000030 kill (REG_2)             ; kill register 3
000032 getlocal (REG_0, this)   ; do the same thing with j...
000033 dup
000034 setlocal (REG_2)
000035 getproperty j
000037 increment_i
000038 setlocal (REG_3)
000039 getlocal (REG_2)
000040 getlocal (REG_3)
000041 setproperty j
000043 kill (REG_3)
000045 kill (REG_2)
000047 getlocal (REG_0, this)
000048 getproperty j
000050 pushint 5000000
000052 iflt -40

バージョンはi = i + 1やや短いです:

000017 getlocal (REG_0, this)   ; push this onto stack
000018 getlocal (REG_0, this)   ; push this onto stack
000019 getproperty i            ; get property "i"
000021 pushbyte 1               ; push 1 onto stack
000023 add                      ; add the two
000024 initproperty i           ; save result to property "i"
000026 getlocal (REG_0, this)   ; increment j...
000027 dup
000028 setlocal (REG_2)
000029 getproperty j
000031 increment_i
000032 setlocal (REG_3)
000033 getlocal (REG_2)
000034 getlocal (REG_3)
000035 setproperty j
000037 kill (REG_3)
000039 kill (REG_2)
000041 getlocal (REG_0, this)
000042 getproperty j
000044 pushint 5000000
000046 iflt -34 
于 2012-08-31T15:41:27.383 に答える
4

この動作を再現することはできません。3つすべてがほぼ同じ時間に見える

Attempt 1
loop 1: 378
loop 2: 396
loop 3: 382

Attempt 2
loop 1: 380
loop 2: 361
loop 3: 361

Attempt 3
loop 1: 375
loop 2: 373
loop 3: 355

ループを10倍に増やすと、次のようになります。

Attempt 1
loop 1: 3707
loop 2: 3663
loop 3: 3653

Attempt 2
loop 1: 3722
loop 2: 3632
loop 3: 3711

[TestLoopSpeed.as]

package
{
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class TestLoopSpeed extends Sprite
    {
        public function TestLoopSpeed()
        {
            var timeNow:Number = getTimer();
            var i:int = 0;

            var startOne:Number = getTimer();
            for (var j:int = 0; j < 5000000; j++)
            {
                i=i+1;
            }
            var endOne:Number = getTimer();


            var startTwo:Number = getTimer();
            i = 0;
            for (var j:int = 0; j < 5000000; j++)
            {
                i++;
            }
            var endTwo:Number = getTimer();

            var startThree:Number = getTimer();
            i = 0;
            for (var j:int = 0; j < 5000000; j++)
            {
                ++i;
            }
            var endThree:Number = getTimer();

            trace("loop 1: " + (endOne - startOne));
            trace("loop 2: " + (endTwo - startTwo));
            trace("loop 3: " + (endThree - startThree));
        }
    }
}

私が理解している限り、i++は最終的にi= i+1と同等です。ただし、その行で割り当てが発生している場合は、iの現在の値が使用され、後の命令でiに1が追加されます。++ iは、この行で他の操作を行う前に、iに1を追加することを意味します。最終的に、これらのオプションのいずれも実際にパフォーマンスに影響を与えるとは思わない。これまでに行ったすべてのテストから、フラッシュプロセスの任意の時点でのCPUスケジューリングが、特定のオペレーターよりも大きな影響を及ぼしているように見える。

テストに使用しているコードに問題がある場合は、それを指摘してください。

編集

コードを更新してwhileループオプションを含めましたが、正の有意差のように見えるものはまだ表示されていません。

loop 1: 3695
loop 2: 3698
loop 3: 3690
loop 4: 3711

loop 1: 3758
loop 2: 3651
loop 3: 3707
loop 4: 3676

[TestLoopSpeed.as]ファンシーなwhileループのプリインクリメントアクションで更新

package
{
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class TestLoopSpeed extends Sprite
    {
        public function TestLoopSpeed()
        {
            var timeNow:Number = getTimer();
            var i:int = 0;

            var startOne:Number = getTimer();
            for (var j:int = 0; j < 50000000; j++)
            {
                i=i+1;
            }
            var endOne:Number = getTimer();


            var startTwo:Number = getTimer();
            i = 0;
            for (var j:int = 0; j < 50000000; j++)
            {
                i++;
            }
            var endTwo:Number = getTimer();

            var startThree:Number = getTimer();
            i = 0;
            for (var j:int = 0; j < 50000000; j++)
            {
                ++i;
            }
            var endThree:Number = getTimer();

            var startFour:Number = getTimer();
            i = 0;
            var j:int = -1;
            while (++j < 50000000)
            {
                ++i;
            }
            var endFour:Number = getTimer();

            trace("loop 1: " + (endOne - startOne));
            trace("loop 2: " + (endTwo - startTwo));
            trace("loop 3: " + (endThree - startThree));
            trace("loop 4: " + (endFour - startFour));
        }
    }
}
于 2012-08-31T03:22:53.910 に答える
2

++および--演算子は、インクリメントとデクリメントのアセンブリコードに似ているように設計されていますが、最近では、コンパイラの進歩によって大きな違いはないはずです。セクションの増減を参照してください

これは、実装の変更またはActionScript仮想マシン の一時的なリグレッションである可能性があります。

于 2012-08-31T03:34:57.113 に答える
0

あなたの質問に対する回答はありませんが、私が試したすべてのループの中で、以下が最速でした。

import flash.utils.getTimer;

var t:int = getTimer();
var i:int = 0, j:int = -1;
while (++j < 5000000) {
    i += 1;
}
trace(getTimer()-t)

これで83ミリ秒になります。

于 2012-08-31T03:31:33.320 に答える
0

あなたが言った両方よりも速いので、i++;使用する代わりに私は提案します。++i;

この良い説明を見てください:より効率的なi++または++iは何ですか?

于 2012-08-31T03:35:43.740 に答える