2012-04-24 42 views
22

Hice la aplicación de prueba rápida para comparar la clasificación LINQ a Array.Sort en mis objetos personalizados. ¡Array.Sort parece extremadamente lento!¿Por qué Array.Sort() es tan lento en comparación con LINQ?

hice mi clase personalizada como esto:

class Person : IComparable<Person> 
{ 
    public int Age { get; set; } 
    public string Name { get; set; } 

    public int CompareTo(Person obj) 
    { 
     return this.Age.CompareTo(obj.Age); 
    } 

    public Person() 
    { } 

} 

Entonces hice mis pruebas de personas en main():

string name = "Mr. Tomek"; 

Random r = new Random(); 
int size = 10000000; 

DateTime start, end; 
Person[] people1 = new Person[size]; 
Person[] people2 = new Person[size]; 

for (int i = 0; i < size; i++) 
{ 
    people1[i] = new Person(); 
    people1[i].Age = r.Next(0, 10000); 
    people1[i].Name = name; 

    people2[i] = new Person(); 
    people2[i].Age = people1[i].Age; 
    people2[i].Name = people1[i].Name; 
} 

Después de ese tiempo he tomado medida de Ordenar por Array.Sort y por LINQ: tiempo

start = DateTime.Now; 
var sort = from s in people2 
      orderby s.Age 
      select s; 
end = DateTime.Now; 
Console.WriteLine("LINQ: "); 
Console.WriteLine((end - start).TotalMilliseconds); 

start = DateTime.Now; 
Array.Sort(people1,((Person p1, Person p2)=>{return p1.CompareTo(p2);})); 
end = DateTime.Now; 

Console.WriteLine("IComparable: "); 
Console.WriteLine((end - start).TotalMilliseconds); 

Console.ReadLine(); 

Linq: alrededor de 1 o 2 milisegundos

Array.Sort: más de 16 SECONDS!

Todas las matrices están ordenadas (LINQ produce una nueva colección y deja oryginal array sin clasificar) pero Array.Sort es extremadamente lenta. ¿Cómo podría ser explicado? (en modo DEBUG y RELEASE Array.Sort falla extremadamente)

Pegué el código con la expresión lambda al ordenar con Array.Sort pero es lo mismo con y sin él. (Persona de clase implementa la interfaz IComparable)

+2

Puede que le interese mi pregunta relacionada. http://stackoverflow.com/questions/10110013/order-of-linq-extension-methods-does-not-affect-performance –

+0

@TomaszSikora: Simplemente puede ordenar llamando a 'Array.Sort (people1)', ya que La implementación 'IComparable ' se usa automáticamente. –

+0

Me di cuenta de algo ... Linq es más rápido al ordenar matrices más grandes. Array.Sort es más rápido cuando Array tiene menos de 100 000 elementos. ¿Por qué está sucediendo eso? –

Respuesta

55

Su consulta de Linq ni siquiera se ejecuta porque no obtiene los resultados. Eso se llama deferred execution. La consulta solo se ejecuta cuando realmente enumera los resultados.

Use algo como var results = sort.ToArray() para ejecutar la consulta, y obtendrá resultados más precisos.

+49

¡El código que no se ejecuta siempre superará la ejecución del código! –

+8

Espero que OP no se sienta tonto. Es un problema ** muy ** común/error que he visto (y probablemente lo he hecho yo mismo): no saber o entender cuándo en realidad estás enumerando un IEnumerable y cuándo lo estás alterando. Creo que más común que esto es el problema en el que te cuesta la eficiencia al enumerar tu IEnumerable varias veces. –

+0

@blesh Sí, seguramente no es lo primero que la gente sabe sobre Linq :) – Botz3000

14

LINQ es flojo. Su people2 no ha sido realmente ordenado, LINQ acaba de crear un "objeto de promesa" temporal que sería ordenado. Para que realmente suceda, debe forzar la evaluación por Console.WriteLine el resultado ordenado, convertirlo en list/array o hacer cualquier otra cosa como esta.

Ver más: deferred execution.

9

declaraciones Linq vuelven IEnumerable<T> o de sabores, esta (o cualquier cosa usando la palabra clave yield) sólo se ejecuta cuando se iterate ella. La mayoría de las acciones disponibles en las bibliotecas de Linq (no todas) are lazy/deferred.

No está iterando, por lo que en realidad no realiza el tipo.

Debe forzar una repetición completa. Pegue los resultados en una lista se repetirá plenamente la enumerable devuelto:

var sort = (from s in people2 
      orderby s.Age 
      select s).ToList(); 

Sólo entonces se puede comparar manzanas con manzanas.

De hecho, en el caso de una especie (orderby), sólo tiene que seleccionar la primera elemento causará una iteración completa como hay que hacer totalmente una especie antes de poder devolver el primer resultado:

var sort = from s in people2 
      orderby s.Age 
      select s; 

var s = sort.First(); 
1

Intenta cambiar esta parte y haz tu prueba una vez más.

start = DateTime.Now; 
    var sort = (from s in people2 
       orderby s.Age 
       select s).ToList(); 
    end = DateTime.Now; 

Este evaluará la expresión LINQ.

Cuestiones relacionadas