Una de mitos: variables fuera y dentro de bucles

Echad un vistazo a este código:

En un método las variables que se usan en el bucle se definen dentro del bucle y en otro fuera.

Pues bien, ¿Cuál de los 2 métodos diríais que tardaría menos en ejecutarse?

Si me hubierais preguntado hubiera dicho que el método testOutsideLoop….

Respuesta

(os adelanto que los tiempos son exactamente los mismos :D)

NOTA: Gracias a Jose Ignacio he detectado que por algún extraño motivo si defino las variables así se compila al mismo código, pero si las defino así:

int runs = 200 * 1000;
int x=0;
int y=0;
int times=0;

el compilado es diferente y también los tiempos 🙂

(Ver comentarios)

Respuestas

  1. El código intermedio generado para ambos métodos es el mismo (sólo cambia la posición de las variables) con lo cual resulta bastante complicado que no pueda suceder otra cosa que la mostrada en los tests. Eso sí, los tests generados para probar que dos códigos iguales se ejecutan en el mismo tiempo son maravillosos. 😉

    1. Ja,ja! como no estaba de acuerdo con lo que decías me puse a replicarlo y fíjate lo que he encontrado.
      El método intermedio generado para ambos métodos es igual si defino las variables en el método testOutsideLoop de la siguiente forma:
      int runs = 200 * 1000, x, y, times;

      private static void testInsideLoop() {
      /* 11*/ long start = System.nanoTime();
      /* 12*/ int counters[] = new int[144];
      /* 13*/ int runs = 0x30d40;
      /* 14*/ for (int i = 0; i < runs; i++) {
      /* 15*/ int x = i % 12;
      /* 16*/ int y = (i / 12) % 12;
      /* 17*/ int times = x * y;
      /* 18*/ counters[times]++;
      }

      /* 20*/ long time = System.nanoTime() – start;
      /* 21*/ System.out.printf("Inside: Average loop time %.1f ns%n", new Object[] {
      /* 21*/ Double.valueOf((double)time / (double)runs)
      });
      }

      private static void testOutsideLoop() {
      /* 25*/ long start = System.nanoTime();
      /* 26*/ int counters[] = new int[144];
      /* 27*/ int runs = 0x30d40;
      /* 28*/ for (int i = 0; i < runs; i++) {
      /* 29*/ int x = i % 12;
      /* 30*/ int y = (i / 12) % 12;
      /* 31*/ int times = x * y;
      /* 32*/ counters[times]++;
      }

      /* 34*/ long time = System.nanoTime() – start;
      /* 35*/ System.out.printf("Outside: Average loop time %.1f ns%n", new Object[] {
      /* 35*/ Double.valueOf((double)time / (double)runs)
      });
      }

      Pero si defino las variables así:

      int runs = 200 * 1000;
      int x=0;
      int y=0;
      int times=0;

      el código generado es diferente (como debía ser en el primer caso!):
      private static void testInsideLoop() {
      /* 11*/ long start = System.nanoTime();
      /* 12*/ int counters[] = new int[144];
      /* 13*/ int runs = 0x30d40;
      /* 14*/ for (int i = 0; i < runs; i++) {
      /* 15*/ int x = i % 12;
      /* 16*/ int y = (i / 12) % 12;
      /* 17*/ int times = x * y;
      /* 18*/ counters[times]++;
      }

      /* 20*/ long time = System.nanoTime() – start;
      /* 21*/ System.out.printf("Inside: Average loop time %.1f ns%n", new Object[] {
      /* 21*/ Double.valueOf((double)time / (double)runs)
      });
      }

      private static void testOutsideLoop() {
      /* 25*/ long start = System.nanoTime();
      /* 26*/ int counters[] = new int[144];
      /* 27*/ int runs = 0x30d40;
      /* 28*/ int x = 0;
      /* 29*/ int y = 0;
      /* 30*/ int times = 0;
      /* 31*/ for (int i = 0; i < runs; i++) {
      /* 32*/ x = i % 12;
      /* 33*/ y = (i / 12) % 12;
      /* 34*/ times = x * y;
      /* 35*/ counters[times]++;
      }

      y los tiempos también 🙂
      Inside: Average loop time 16,5 ns
      Outside: Average loop time 19,1 ns
      Inside: Average loop time 14,6 ns
      Outside: Average loop time 15,6 ns
      Inside: Average loop time 13,5 ns
      Outside: Average loop time 13,6 ns
      Inside: Average loop time 13,4 ns
      Outside: Average loop time 13,3 ns
      Inside: Average loop time 13,5 ns
      Outside: Average loop time 13,7 ns
      Inside: Average loop time 13,7 ns
      Outside: Average loop time 13,3 ns
      Inside: Average loop time 13,3 ns
      Outside: Average loop time 13,2 ns
      Inside: Average loop time 13,2 ns
      Outside: Average loop time 13,5 ns
      Inside: Average loop time 13,5 ns
      Outside: Average loop time 16,3 ns
      Inside: Average loop time 13,4 ns
      Outside: Average loop time 13,2 ns

      1. Avatar de José Ignacio Aguillo
        José Ignacio Aguillo

        En realidad con esas modificaciones sólo cambia la parte de inicialización de las tres variables a 0, el resto del código intermedio es equivalente :-).

        Tengo un resultado de comparación de los dos códigos intermedios con WinMerge que lo demuestra. 😉

        Además con esos resultados estamos demostrando justamente lo contrario de lo que parecía intuirse, ya que aparentemente declarar las variables dentro del bucle es menos costoso.

Deja un comentario