2012-08-31 18 views
5

przetestować ten kod Flash:Dlaczego i = i + 1 jest szybsze niż 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 

Dlaczego i=i+1 szybciej w ActionScript 3, gdy jest wolniejszy w innych?

Przepraszam, popełniam błąd. Powyższy kod stosuje się w tym samym czasie. , ale jeśli wprowadzisz go do funkcji, a wynik będzie inny.

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

Można razy 10 długości pętli, a także upewnić się, że naprawdę jest różnica? – scientiaesthete

+0

Co masz na myśli mówiąc "wolniej w innych?" Inne języki programowania? Które? –

+0

Mała uwaga poboczna: Ma znaczenie, jeśli posiadasz release-/debugbuild (ustawienie "zezwalaj na debugowanie" w FlashIDE), a wyniki mogą się różnić w odtwarzaczu release i debugplayer. http://jacksondunstan.com ma wiele bardzo dogłębnych testów wydajności dla kilku graczy. –

Odpowiedz

5

Gdzie znajduje się pętla może mieć duży wpływ na wydajność. Jeśli twoja pętla znajduje się w funkcji, Flash przeprowadzi obliczenia z wykorzystaniem lokalnych rejestrów. Pętla zawierający i++ wytwarza zatem następujące rozkazy:

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 

pętla zawierająca i = i + 1 wytwarza następujące:

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++ szybciej niż i = i + 1 tu od inclocal_i modyfikuje rejestr bezpośrednio, bez konieczności otwierania zarejestruj się na stos i zapisz go z powrotem.

Pętla staje się znacznie mniej wydajna po umieszczeniu jej w skrypcie klatki. Flash zapisze zadeklarowane zmienne jako zmienne klasy. Dostęp do nich wymaga więcej pracy. W i++ Wyniki pętli w następujących przypadkach:

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 

Wersja i = i + 1 jest nieco krótszy:

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

Podoba mi się twoja odpowiedź o wiele lepiej niż moja :) w jaki sposób uzyskujesz opkodami jakoś zmodyfikowałeś mm.cfg? – shaunhusain

+1

Napisałem dezasembler AS3. Możesz to sprawdzić na: http://flaczki.net46.net/codeump/. Może być odporny na optymalizację wydajności. – cleong

+0

Dziękuję, to niesamowite! Przenoszę niektóre z nich do HTML5/JS, więc muszę oprzeć się nieco na kwestiach AS3, ale na pewno zarchiwizuję to, by niedługo się przekonać. – shaunhusain

4

nie może replikować to zachowanie wszystkich trzech wydaje się być w tym samym czasie dla mnie

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 

zwiększenie pętle przez współczynnik 10 mam te czasy:

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

O ile rozumiem, i ++ jest ostatecznie równoznaczne z i = i + 1; z tym wyjątkiem, że jeśli w tym wierszu pojawi się przypisanie, wówczas zostanie użyta bieżąca wartość i, a późniejsza instrukcja doda jeden do i. ++ oznacza po prostu dodanie 1 do i przed wykonaniem jakichkolwiek innych operacji na tej linii. Uważam, że żadna z tych opcji nie powinna wpływać na wydajność, która wynika z każdego przeprowadzonego testu, że planowanie procesora w danej chwili dla procesu flashowego ma większy wpływ niż jakikolwiek operator.

Jeśli coś jest nie tak z kodem, którego używam do przetestowania, proszę go wskazać.

Edit

uaktualniony kod do włączenia opcji pętli while, jeszcze nie wszystko, co wygląda jak pozytywny znaczącej różnicy zobaczyć:

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] Updated ozdobnego chwilę pętla preinkrementuj działanie

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

nie mam odpowiedź na twoje pytanie, ale następujące rzeczy były najszybsze spośród wszystkich pętli, które wypróbowałem.

import flash.utils.getTimer; 

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

Daje to 83 ms.

2

++ oraz - operatory zostały zaprojektowane tak, aby przypominały kod assemblera dla przyrostu i dekrementacji, ale obecnie nie powinno to mieć większego wpływu na postęp kompilatorów. See section increase and decrease

Może to być zmiana w implementacji lub tymczasowy regression w wirtualnej maszynie actionscript.

0

Proponuję zamiast i++; użyć ++i; Ponieważ jest szybszy niż oba wymienione.

Spójrz na to dobre wytłumaczenie: What is more efficient i++ or ++i?

+0

Warto wspomnieć, że zmienna nie będzie zachowywać tej samej wartości po każdej z tych operacji, co oznacza, że ​​nie są wymienne bez zmiany kodu, który używa tej zmiennej. –

0

zależy także wszystko na język. Maby w AS3 $ i = $ i + 1 jest szybsza, w PHP $ i ++ jest. Ale jak Almas Adilbek mówi. ++ ++ i jest najszybszy.

Przykład

<?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); 
?> 
Powiązane problemy