2009-05-28 14 views

Respuesta

9

Ok. Aquí está mi opinión sobre por qué?

Si convierte a ambas secuencias de comandos de código de bytes, se puede observar que

  1. ForInLoop utiliza rango. El iterador se usa para avanzar durante cada ciclo. La comparación (<) se realiza directamente en int (o Integer) para determinar si se cumplió o no la condición de salida
  2. ForLoop usa el incremento tradicional, comprueba las condiciones y realiza acciones. Para comprobar la condición i < 10000000, usa el ScriptBytecodeAdapter de Groovy .compareLessThan. Si usted cava profundamente en el código de ese método, se encuentra a ambos lados de la comparación se toma en como objeto y hay tantas cosas que suceden, fundición, comparándolos como objeto, etc.

ScriptBytecodeAdapter .compareLessThan - >ScriptBytecodeAdapter .compareTo ->DefaultTypeTransformation .compareTo

Hay otras clases en el paquete typehandling que implementa el método compareTo específicamente para los tipos de datos de matemáticas, no está seguro de por qué no se están utilizando, (si es que no están siendo utilizados)

Sospecho que ese es el motivo por el que el segundo ciclo tarda más. De nuevo, por favor corrígeme si me equivoco o me falta algo ...

+0

Eso casi lo explica. Sé que Java-style for loop ofrece más flexibilidad en lo que puede hacer, pero seguramente podrían haber aplicado alguna optimización a su forma más básica (y la más utilizada) para que funcione tan bien como el bucle for..in? Esa es una pequeña trampa de rendimiento para las personas que vienen de Java o C# ... – Xiaofu

+0

Nadie espera tanta disparidad en estas dos operaciones. Áreas donde Groovy podría mejorar, especialmente dado que un código similar en Java se ejecuta en 300 mS. –

+1

+1 para mirar el bytecode. – Leonel

2

En sus pruebas, asegúrese de "calentar" la JVM antes de tomar la medida, de lo contrario, puede terminar desencadenando varias acciones de inicio en la plataforma (carga de clases, compilación JIT). Ejecute sus pruebas muchas veces seguidas también. Además, si realizaba la segunda prueba mientras se realizaba un recolección de basura, eso podría tener un impacto. Intente ejecutar cada una de sus pruebas 100 veces e imprima los tiempos después de cada prueba, y vea lo que eso le dice.

1

Si puede eliminar artefactos potenciales del tiempo de inicio como Jim sugiere, entonces me atrevería a adivinar que el estilo de Java para bucle en Groovy no está tan bien implementado como el bucle de estilo original de Groovy. Solo se agregó a partir de v1.5 después de las solicitudes de los usuarios, por lo que tal vez su implementación fue algo secundario.

¿Has echado un vistazo al bytecode generado para tus dos ejemplos para ver si hay alguna diferencia? Hubo una discusión sobre el rendimiento maravilloso here en el que uno de los comentarios (de una 'johnchase') dice lo siguiente:

me pregunto si la diferencia se vio relacionado con la manera maravillosa de usos números (primitivas) - ya que envuelve todas las primitivas en sus clases de envoltura de Java equivalentes (int -> Integer), me imagino que eso desaceleraría bastante las cosas. Me interesaría ver el rendimiento del código de Java que realiza un bucle de 10,000,000 usando las clases contenedoras en lugar de las entradas.

¿Entonces quizás el Groovy for loop original no sufra de esto? Solo especulación de mi parte realmente.

+0

Xiaofu, estos son buenos puntos. Lo que encuentro confuso es que el ciclo inferior debería ser el más rápido, ya que trata solo con enteros, no con enteros (aunque el tipo de j no está especificado). El ciclo superior debería ser más lento dada la secuencia. –

Cuestiones relacionadas