loop - for java 8
¿Es++ i realmente más rápido que i++ en for-loops en java? (11)
Descompile con "javap -c YourClassName" y vea el resultado y decida a partir de eso. De esta forma, verá lo que el compilador realmente hace en cada caso, no lo que cree que hace. De esta forma, también verá POR QUÉ una forma es más rápida que la otra.
En java generalmente hago un ciclo de for-loop como el siguiente:
for (int i = 0; i < max; i++) {
something
}
Pero recientemente un colega lo tipeó así:
for (int i = 0; i < max; ++i) {
something
}
Dijo que este último sería más rápido. ¿Es eso cierto?
En Java no debería haber diferencia: cualquier compilador moderno * debería generar el mismo código de bytes (solo un iinc
) en ambos casos, ya que el resultado de la expresión de incremento no se está utilizando directamente .
Hay una tercera opción, sigue siendo el mismo código de bytes * :
for (int i = 0; i < max; i += 1) {
something
}
* probado con el compilador de Eclipse
En Java no hay tal diferencia. El código interpertes de la máquina Java y no importa si escribe ++ i o i ++, se convertirá en código de bytes para exactamente el mismo conjunto de instrucciones.
Pero en C / C ++ hay una gran diferencia y si no está utilizando ningún indicador de optimización, entonces su ciclo puede ser más lento hasta 3 veces.
El uso de indicadores de optimización como -O / -O3 obligará al compilador a simplificar el código de ensamblaje de salida (en la mayoría de los casos) y, por lo tanto, a hacerlo más rápido (en la mayoría de los casos).
Esta pregunta necesitaba un código de bytes de Java. Considera el siguiente código:
public class PostPre {
public static void main(String args[]) {
int n = 5;
loop1(n);
loop2(n);
}
public static void loop1(int n) {
for (int i = 0; i < n; i++) {}
}
public static void loop2(int n) {
for (int i = 0; i < n; ++i) {}
}
}
Ahora compila y desensambla:
$ javac PostPre.java; javap -c PostPre.class
Compiled from "PostPre.java"
public class PostPre {
public PostPre();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1
2: iload_1
3: invokestatic #2 // Method loop1:(I)V
6: iload_1
7: invokestatic #3 // Method loop2:(I)V
10: return
public static void loop1(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
public static void loop2(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
}
loop1()
y loop2()
tienen el mismo código de bytes.
Incluso si lo es, lo cual dudo mucho, su colega realmente debería tener mejores cosas para pasar el tiempo aprendiendo que cómo optimizar una expresión de bucle.
Incluso si uno fuera más rápido, a nadie le importa en los días de HotSpot. Lo primero que hace el JIT es eliminar todas las optimizaciones que hizo javac. Después de eso, todo queda en el JIT para hacerlo rápido.
No será más rápido. El compilador y la JVM con el JIT harán picadillo de tan insignificantes diferencias.
Puede utilizar las técnicas habituales de optimización de bucle para obtener ventajas de velocidad, como desenrollar, si corresponde.
No, eso no es verdad. Puede medir el rendimiento al sincronizar cada ciclo para una gran cantidad de iteraciones, pero estoy bastante seguro de que serán las mismas.
El mito vino de C, donde ++i
se consideró más rápido que i++
porque el primero se puede implementar aumentando y luego devolviéndolo. Esto último podría implementarse copiando el valor de i en una variable temporal, incrementando i, y luego devolviendo el valor temporal. La primera versión no necesita hacer la copia temporal y muchas personas suponen que es más rápida. Sin embargo, si la expresión se utiliza como una declaración, los compiladores de C modernos pueden optimizar la copia temporal de manera que no haya diferencia en la práctica.
No, no habrá ninguna diferencia.
Esto vino de C ++, pero incluso allí no habría ninguna diferencia en este caso. Donde hay una diferencia es donde yo soy un objeto. i ++ tendría que hacer una copia adicional del objeto, ya que tiene que devolver el valor original sin modificar del elemento, mientras que ++ puede devolver el objeto modificado para que guarde una copia.
En c ++ con el objeto definido por el usuario, el costo de una copia puede ser significativo, por lo que definitivamente vale la pena recordarlo. Y debido a esto, las personas tienden a usarlo también para variables int, ya que de todos modos es igual de bueno ...
Para cualquier optimizador razonablemente capaz, serán exactamente iguales. Si no está seguro, mire el bytecode de salida o perfíllo.
Prueba esto en tu entorno
public class IsOptmized {
public static void main(String[] args) {
long foo; //make sure the value of i is used inside the loop
long now = 0;
long prefix = 0;
long postfix = 0;
for (;;) {
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
foo += i;
}
postfix = System.currentTimeMillis() - now;
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; ++i) {
foo += i;
}
prefix = System.currentTimeMillis() - now;
System.out.println("i++ " + postfix + " ++i " + prefix + " foo " + foo);
}
}
}
El mío me da
i++ 1690 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1611 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1692 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
Entonces, aunque no sea tanto, supongo que hay una diferencia