2012-08-31 99 views
5

測試此代碼在Flash:爲什麼i = i + 1比i ++快?

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 
+3

您可以10倍環路長度,並確保真的有區別嗎? – scientiaesthete

+0

你是什麼意思「其他人比較慢?」其他編程語言?哪個? –

+0

一個小方面說明:如果你有一個release-/debugbuild(在FlashIDE中的'允許調試'設置),那麼這很重要,並且結果在發佈版和調試版中也會有所不同。 http://jacksondunstan.com對多個玩家進行了很多非常深入的性能測試。 –

回答

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 + 1這裏更快,因爲inclocal_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 
+0

我喜歡你的答案比我的好多了:)你怎麼得到操作碼,你只是修改mm.cfg莫名其妙? – shaunhusain

+1

我寫了一個AS3拆裝器。你可以在http://flaczki.net46.net/codedump/查看。性能優化可能會很難。 – cleong

+0

謝謝你真棒!我正在過渡到HTML5/JS,所以我不得不依靠AS3的東西一點,但我一定會將其歸檔,以便儘快結賬。 – shaunhusain

4

我不能複製這種行爲這三個似乎是差不多的時候,我

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。最終,我不認爲這些選項中的任何一個都會真正影響從我做過的每個測試中看出的性能,因爲在任何給定時刻,對於閃存進程而言,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] 更新花式而循環預增量動作

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)); 
     } 
    } 
} 
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毫秒。

2

++和 - 操作符被設計成類似彙編代碼的增量和減量,但是現在它不應該與編譯器的進步有很大的區別。 See section increase and decrease

它可能是實施中的更改,或者是actionscript虛擬機中的臨時regression

0

我建議不要使用i++;使用++i;因爲它比你提到的要快。

看這很好的解釋:What is more efficient i++ or ++i?

+0

值得一提的是,在每個操作之後,變量不會保持相同的值,這意味着如果不更改使用此變量的代碼,它們就不可互換。 –

0

還取決於所有的語言。 Maby在AS3 $ i = $ i + 1中速度更快,在PHP $ i ++中速度更快。但像Almas Adilbek所說的那樣。 ++ $ i是最快的。

<?php 
    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     $i++; 
    } 

    $end = microtime(); 

    echo 'First complete in: ' . ($end - $start); 

    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     $i = $i+1; 
    } 

    $end = microtime(); 

    echo 'Second complete in: ' . ($end - $start); 

    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     ++$i; 
    } 

    $end = microtime(); 

    echo 'Third complete in: ' . ($end - $start); 
?> 
相關問題