2012-03-05 7 views
7

Por curiosidad quise probar el número de tics para comparar una Lista Generica contra una Lista de Arrays.¿Por qué una lista simple <T> parece ser más lenta que una ArrayList?

Y para el siguiente código cuando miro los cronómetros, ArrayList parece más rápido.

¿Hice algo mal o hay una explicación para esto? (Yo creía sto Lista ser mucho más rápido)

Código tesing y la salida por debajo de:

private static void ArrayListVsGenericList() 
{ 
    // Measure for ArrayList 
    Stopwatch w0 = new Stopwatch(); 
    w0.Start(); 

    ArrayList aList = new ArrayList(); 

    for (int i = 0; i < 1001; i++) 
    { 
     Point p = new Point(); 
     p.X = p.Y = i; 

     aList.Add(p); 
    } 

    foreach (Point point in aList) 
    { 
     int v0 = ((Point) aList[8]).X; //unboxing 
    } 


    w0.Stop(); 

    // Measure for Generic List<Point> 
    Stopwatch w1 = new Stopwatch(); 
    w1.Start(); 

    List<Point> list = new List<Point>(); 

    for (int i = 0; i < 1001; i++) 
    { 
     Point p = new Point(); 
     p.X = p.Y = i; 

     list.Add(p); 
    } 


    foreach (var point in list) 
    { 
     int v1 = list[8].X; 
    } 

    w1.Stop(); 

    Console.WriteLine("Watch 0 : " + w0.ElapsedTicks); 
    Console.WriteLine("Watch 1 : " + w1.ElapsedTicks); 
    Console.WriteLine("Watch 0 > Watch 1 : " + (w0.ElapsedTicks > w1.ElapsedTicks)); 
} 

enter image description here

+0

No creo que esta prueba sea confiable. La secuencia de ejecución del código es importante, para empezar. Agregar en la segunda lista puede sufrir las asignaciones anteriores. También 1000 elementos son un conjunto pequeño. Definitivamente debe separar el relleno y obtener de los dos tipos de listas en dos programas diferentes y luego probarlos usando un generador de perfiles, no cronómetros. – vulkanino

+0

¿Cómo se ve al usar 'int's en lugar de' Point's? Al probar la lista genérica primero? –

+0

Bueno, cuando aumente el número de elementos a 1000001, los genéricos son más rápidos. ¿Pero significa esto que los genéricos no se pueden considerar como MÁS RÁPIDOS cuando se trabaja en pequeños conjuntos de elementos? – pencilCake

Respuesta

7

cambiar su programa de prueba para ejecutar su método de al menos dos veces y pasar por alto la primera ejecución . Los resultados son causados ​​por la generación de código y jits para el tipo concreto List<Point>.

En mi máquina esto lleva a la siguiente salida:

Watch 0 : 154 
    Watch 1 : 74 
    Watch 0 > Watch 1 : True 

¿Qué es más o menos lo que uno esperaría.

+0

¡Tiene razón! En la segunda carrera fue mucho más rápido incluso para un pequeño conjunto de elementos. (Entonces, en este caso, si ejecuto NGEN.exe; Aseguraría que la primera carrera sea rápida también para la Lista genérica, supongo) – pencilCake

5

No eliminó los primeros efectos de ejecución como JIT. Los genéricos deben compilarse una vez para cada argumento de tipo de valor.

ArrayList ya está precompilado con ngen.

List<T> solo está precompilado para ciertos tipos de parámetros (he leído que las bibliotecas centrales ejemplifican algunos de los genéricos más importantes para los argumentos comunes, como object, bool, int, ...), en todo caso. Por lo tanto, incurrirá en un costo de una sola vez.

También debe tener en cuenta que la mayor parte del costo de rendimiento de ArrayList es indirecto: el boxeo ejerce una mayor presión sobre el GC y utiliza más memoria. Pero tu prueba no medirá eso. El costo de producir más basura también depende de cuántos otros objetos existen y de la vida útil de los mismos.

Cuando escribe pruebas, debe ejecutar todos los códigos una vez antes de la prueba real o utilizar tantas iteraciones que los costos de una vez son insignificantes. También es importante utilizar una compilación de lanzamiento y ejecutar sin el depurador conectado.

Cuestiones relacionadas