2012-02-20 12 views
5

Me pregunto por qué el siguiente fragmento no da el resultado esperado. Clasifica una matriz aleatoria no demasiado pequeña y usa 3 métodos diferentes para ella. Yo estaba esperando la velocidad para salir como así:¿Qué le pasó a Array.Sort() en .NET 4.0? ¿TrySZSort() se ha ido?

  1. Array.Sort() - más rápido mediante el uso de la función TrySZSort nativa por lo que recuerdo de .NET 2.0
  2. orden descendente utilizando la clase Comparer encargo
  3. El tipo de expresión lambda.

El Código:

class DescComparer : IComparer<double> { 
    // simple comparison 
    // (yes, its not exactly correct ...) 
    public int Compare(double x, double y) { 
     return (x > y) ? -1 : 1; 
    } 
} 
static void Main(string[] args) { 
    Stopwatch sw = new Stopwatch(); 
    Random rand = new Random(); 
    DescComparer comparer = new DescComparer(); 
    double[] a = new double[1000000]; 
    for (int r = 0; r < 20; r++) { 

     // init array 
     for (int i = 0; i < a.Length; i++) a[i] = rand.NextDouble(); 
     sw.Restart(); 
     Array.Sort(a); 
     sw.Stop(); 
     Console.WriteLine("ascending took: {0} ms ", sw.ElapsedMilliseconds); 

     // init array 
     for (int i = 0; i < a.Length; i++) a[i] = rand.NextDouble(); 
     sw.Restart(); 
     Array.Sort<double>(a, comparer); 
     sw.Stop(); 
     Console.WriteLine("descending took: {0} ms ", sw.ElapsedMilliseconds); 

     // init array 
     for (int i = 0; i < a.Length; i++) a[i] = rand.NextDouble(); 
     sw.Restart(); 
     Array.Sort<double>(a, (x,y) => -x.CompareTo(y)); 
     sw.Stop(); 
     Console.WriteLine("desc lambda took: {0} ms ", sw.ElapsedMilliseconds); 

    } 
    Console.Read(); 
} 

Pero, extrañamente, se dicta la siguiente:

ascending took: 514 ms 
descending took: 537 ms 
desc lambda took: 915 ms 
ascending took: 511 ms 
descending took: 492 ms 
desc lambda took: 923 ms 
ascending took: 511 ms 
descending took: 483 ms 
desc lambda took: 912 ms 
ascending took: 511 ms 
descending took: 485 ms 
desc lambda took: 914 ms 
ascending took: 518 ms 
descending took: 485 ms 
desc lambda took: 924 ms 
... a.s.o. ... 

Así, el lambda es muy lento. Pero, ¿cómo es posible, el sencillo Array ascendente? ¿La hierba ya no es más rápida? ¿Lo es, porque Array.Sort (T [], Comparer) se ha mejorado o simplemente se ha eliminado TrySZSort? ¿O me perdí algo?

(versión de lanzamiento, sin depuración, sin reflector disponible en este momento;)) ¡Gracias!

ACTUALIZACIÓN: De acuerdo con la sugerencia de @Reed Copsey, la expresión lambda no es justa. Traté de cambiarlo al mismo que hace el comparador. La velocidad subió. Asc/lambda pasó del 55% -> 75%. Por lo tanto, todavía es considerablemente más lento.

+1

No puedo explicar el resultado de rendimiento, pero al mirar el reflector, TrySZSort no se ha ido, y se llama por tanto '' sort' y Ordenar 'métodos, pero solo cuando el comparador es nulo o predeterminado. –

+0

@ Meta-Knight hm. ¡interesante! Entonces parece que el lado manejado se atoró un poco. ¡Gracias por contar! –

+1

Sí, Array.Sort() se reescribió en .NET 4. Hay varios clasificadores.Es posible que esté recibiendo uno que no se quede atascado en un ciclo sin fin cuando el comparador se porta mal. Chase down mirando el código fuente comentado disponible de la fuente de referencia. –

Respuesta

5

Por lo tanto, el lambda realmente es el más lento. Pero, ¿cómo es posible, el sencillo Array ascendente? ¿La hierba ya no es más rápida? ¿Lo es, porque Array.Sort (T [], Comparer) se ha mejorado o simplemente se ha eliminado TrySZSort? ¿O me perdí algo?

Bueno, hay dos problemas aquí. En primer lugar, esto realmente depende de su construcción y el sistema -

En mi sistema, en x64, Array.Sort()es el más rápido, por una cantidad significativa:

ascending took: 192 ms 
descending took: 248 ms 
desc lambda took: 326 ms 
ascending took: 194 ms 
descending took: 247 ms 
desc lambda took: 326 ms 

en x86, las cosas son un poco diferentes - pero no tiene casi la misma importancia que muestra:

ascending took: 235 ms 
descending took: 223 ms 
desc lambda took: 325 ms 
ascending took: 234 ms 
descending took: 222 ms 
desc lambda took: 325 ms 

¿Tenía el host visual studio conectado cuando ejecutó estos tiempos? Incluso una compilación de lanzamiento será dramáticamente más lenta si se ejecuta dentro de VS (es decir, F5 en lugar de Ctrl + F5 de forma predeterminada).


También tenga en cuenta que su prueba no es completamente justa, con respecto a la lambda. Debe utilizar el mismo mecanismo para la prueba, lo que sería:

Array.Sort<double>(a, (x, y) => (x > y) ? -1 : 1); 
+0

Derecha. La diferencia con lambda (X86) es menos significativa. Pero las proporciones de velocidad asc/desc sin lambda son más o menos las mismas: 5%. –