2012-08-31 42 views
5

Prueba este código en Flash:¿Por qué i = i + 1 es más rápido que 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 

¿Por qué es más rápido i=i+1 en ActionScript 3 cuando es más lenta que en otros?

Disculpe, me equivoco. El código anterior utiliza el mismo tiempo. pero si lo pone en funcionamiento, y el resultado será diferente.

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

puede usted Tiempos 10 la longitud del bucle, y asegúrese de que realmente hay una diferencia? – scientiaesthete

+0

¿Qué quiere decir con "más lento en los demás"? Otros lenguajes de programación? ¿Cuáles? –

+0

Una pequeña nota al margen: no importa si tiene una configuración release/debugbuild ('permiso de depuración' en FlashIDE), y los resultados también podrían variar en un release-and debugplayer. http://jacksondunstan.com tiene muchas pruebas de rendimiento muy detalladas para varios jugadores. –

Respuesta

5

Cuando el bucle está situada pueden tener un gran impacto en el rendimiento. Si su bucle está dentro de una función, Flash realizará cálculos usando registros locales. El bucle que contiene i++ produce por lo tanto los siguientes códigos de operación:

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 

El bucle que contiene i = i + 1 produce los siguientes:

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++ es más rápido que i = i + 1 aquí desde inclocal_i modifica el registro directamente, sin tener que cargar el regístrese en la pila y guárdela de nuevo.

El bucle se vuelve mucho menos eficiente cuando lo coloca dentro de un script de marco. Flash almacenará las variables declaradas como variables de clase. Acceder a esos requiere más trabajo. Los resultados i++ de bucle en el siguiente:

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 

La versión i = i + 1 es algo más corto:

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

Me gusta mucho más tu respuesta que la mía :) ¿Cómo obtienes los códigos de operación? ¿Acabas de modificar mm.cfg de alguna manera? – shaunhusain

+1

Escribí un desarmador AS3. Puede verificarlo en: http://flaczki.net46.net/codedump/. Puede ser resistente para la optimización del rendimiento. – cleong

+0

¡Gracias eso es increíble! Estoy haciendo la transición a HTML5/JS, así que tengo que recurrir un poco al material de AS3 por un tiempo, pero definitivamente archivaré eso para verlo pronto. – shaunhusain

4

No puedo reproducir este comportamiento los tres parecen ser aproximadamente el mismo tiempo para mí

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 

El aumento de los bucles en un factor de 10 Tengo estos tiempos:

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

Por lo que yo entiendo, i ++ es en última instancia equivalente a i = i + 1; con la excepción de que si una asignación está ocurriendo en esa línea, entonces se usaría el valor actual de i y una instrucción posterior agregaría uno a i. ++ simplemente significa agregar 1 a i antes de realizar cualquier otra operación en esta línea. En última instancia, no creo que ninguna de estas opciones realmente afecte el rendimiento. De cada prueba que he hecho, parece que la programación de la CPU en un momento dado para el proceso de memoria flash tiene más efecto que cualquier operador dado.

Si hay algún problema con el código que estoy usando para probar, por favor indíquelo.

Editar

ha actualizado el código para incluir la opción de bucle while, todavía no ver todo lo que se ve como una diferencia significativa positiva:

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] actualiza con lujo, mientras acción de preincremento de bucle

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

No tengo una respuesta a su pregunta, pero el siguiente ha sido el más rápido entre todos los loops que probé.

import flash.utils.getTimer; 

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

Esto me da 83 ms.

2

++ y - los operadores se diseñaron para parecerse al código de ensamblado para incrementar y disminuir, pero hoy en día no debería hacer mucha diferencia con el avance de los compiladores. See section increase and decrease

Podría ser un cambio en la implementación o un regression temporal en la máquina virtual ActionScript.

0

Sugiero en lugar de i++; use ++i; Porque es más rápido que los dos que mencionó.

Mira esta buena explicación: What is more efficient i++ or ++i?

+0

Vale la pena mencionar que una variable no tendrá el mismo valor después de cada una de esas operaciones, lo que significa que no son intercambiables sin alterar el código que usa esta variable. –

0

depende también de todo el lenguaje. Maby en AS3 $ i = $ i + 1 es más rápido, en PHP $ i ++ es. Pero como dice Almas Adilbek. El ++ $ i es el más rápido.

Ejemplo

<?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); 
?> 
Cuestiones relacionadas