Digamos que necesita tener una lista / matriz de enteros que necesita iterar con frecuencia, y me refiero con mucha frecuencia. Las razones pueden variar, pero digamos que está en el corazón del bucle más interno de un procesamiento de alto volumen.
En general, uno optaría por usar Listas (Lista) debido a su flexibilidad de tamaño. Además de eso, la documentación de msdn afirma que las Listas usan una matriz internamente y deben funcionar igual de rápido (un vistazo rápido con Reflector lo confirma). Nunca, hay algunos gastos generales involucrados.
¿Alguien realmente midió esto? ¿iterar 6M veces a través de una lista tomaría el mismo tiempo que una matriz?
T[]
vs.List<T>
puede hacer una gran diferencia de rendimiento. Acabo de optimizar una aplicación extremadamente intensiva (anidada) para pasar de listas a matrices en .NET 4.0. Esperaba una mejora del 5% al 10%, ¡pero obtuve más del 40% de aceleración! No hay otros cambios que pasar directamente de la lista a la matriz. Todas las enumeraciones se hicieron conforeach
declaraciones. Sobre la base de la respuesta de Marc Gravell, parece queforeach
conList<T>
es particularmente malo.Respuestas:
Muy fácil de medir ...
En una pequeña cantidad de código de procesamiento de lazo cerrado donde sé que la longitud es fija , uso matrices para ese pequeño bit adicional de micro-optimización; las matrices pueden ser marginalmente más rápidas si usa el indexador / para el formulario, pero el IIRC cree que depende del tipo de datos en la matriz. Pero a menos que necesite micro-optimizar, manténgalo simple y use
List<T>
etc.Por supuesto, esto solo se aplica si está leyendo todos los datos; un diccionario sería más rápido para búsquedas basadas en claves.
Aquí están mis resultados usando "int" (el segundo número es una suma de verificación para verificar que todos hicieron el mismo trabajo):
(editado para corregir errores)
basado en la plataforma de prueba:
fuente
Resumen:
Matriz necesita usar:
Lista necesita usar:
LinkedList necesita usar:
Más detalles:
Mucho más detalles:
https://stackoverflow.com/a/29263914/4423545
fuente
Creo que el rendimiento será bastante similar. La sobrecarga que está involucrada cuando se usa una lista frente a una matriz es, en mi humilde opinión, cuando agrega elementos a la lista, y cuando la lista tiene que aumentar el tamaño de la matriz que está utilizando internamente, cuando se alcanza la capacidad de la matriz.
Suponga que tiene una Lista con una capacidad de 10, luego la Lista aumentará su capacidad una vez que desee agregar el undécimo elemento. Puede disminuir el impacto en el rendimiento inicializando la Capacidad de la lista en la cantidad de elementos que contendrá.
Pero, para saber si iterar sobre una Lista es tan rápido como iterar sobre una matriz, ¿por qué no lo compara?
En mi sistema; iterar sobre la matriz tomó 33 ms; iterar sobre la lista tomó 66 ms.
Para ser sincero, no esperaba que la variación fuera tanto. Entonces, puse mi iteración en un bucle: ahora, ejecuto ambas iteraciones 1000 veces. Los resultados son:
Ahora, la variación ya no es tan grande, pero aún así ...
Por lo tanto, he iniciado .NET Reflector, y el captador del indexador de la clase Lista se ve así:
Como puede ver, cuando usa el indexador de la Lista, la Lista realiza una verificación si no está saliendo de los límites de la matriz interna. Este cheque adicional tiene un costo.
fuente
si solo está obteniendo un valor único de cualquiera de ellos (no en un bucle), ambos hacen la verificación de límites (está en código administrado, recuerde) es solo que la lista lo hace dos veces. Vea las notas más adelante para saber por qué esto probablemente no sea un gran problema.
Si está utilizando el suyo propio (int int i = 0; i <x. [Length / Count]; i ++), la diferencia clave es la siguiente:
Si está utilizando foreach, la diferencia clave es la siguiente:
La verificación de límites a menudo no es gran cosa (especialmente si está en una CPU con una tubería profunda y predicción de ramificación, la norma para la mayoría de estos días), pero solo su propio perfil puede decirle si eso es un problema. Si está en partes de su código donde está evitando las asignaciones de montón (buenos ejemplos son bibliotecas o en implementaciones de hashcode), entonces asegurarse de que la variable se escriba como List not IList evitará esa trampa. Como siempre perfil si importa.
fuente
[ Ver también esta pregunta ]
Modifiqué la respuesta de Marc para usar números aleatorios reales y en realidad hago el mismo trabajo en todos los casos.
Resultados:
Compilado como lanzamiento bajo VS 2008 SP1. Ejecutando sin depurar en un [email protected], .NET 3.5 SP1.
Código:
fuente
Las mediciones son buenas, pero obtendrás resultados significativamente diferentes dependiendo de lo que estés haciendo exactamente en tu ciclo interno. Mide tu propia situación. Si está utilizando subprocesos múltiples, eso solo es una actividad no trivial.
fuente
De hecho, si realiza algunos cálculos complejos dentro del bucle, entonces el rendimiento del indexador de matriz frente al indexador de lista puede ser tan marginalmente pequeño que, eventualmente, no importa.
fuente
Aquí hay uno que usa Diccionarios, IEnumerable:
fuente
No intente agregar capacidad aumentando el número de elementos.
Actuación
fuente
Me preocupaba que los puntos de referencia publicados en otras respuestas aún dejaran espacio para que el compilador optimizara, eliminara o combinara bucles, así que escribí uno que:
El resultado es que una matriz directa tiene un rendimiento aproximadamente 250% mejor que el acceso a una matriz envuelta en una lista IL:
Aquí está el código:
fuente
Como List <> usa arrays internamente, el rendimiento básico debe ser el mismo. Dos razones por las cuales la Lista podría ser un poco más lenta:
Para verificar si hay alguna diferencia para usted, probablemente sea mejor ajustar las funciones de temporización publicadas a una lista del tamaño que planea usar y ver cómo son los resultados para su caso especial.
fuente
Como tenía una pregunta similar, esto me dio un comienzo rápido.
Mi pregunta es un poco más específica, '¿cuál es el método más rápido para una implementación de matriz reflexiva'?
Las pruebas realizadas por Marc Gravell muestran mucho, pero no exactamente el tiempo de acceso. Su sincronización incluye el bucle sobre la matriz y las listas también. Como también se me ocurrió un tercer método que quería probar, un 'Diccionario', solo para comparar, extendí el código de prueba hist.
Primero, hago una prueba usando una constante, lo que me da un cierto tiempo, incluido el bucle. Este es un momento 'desnudo', excluyendo el acceso real. Luego hago una prueba con el acceso a la estructura del tema, esto me da tiempo y 'sobrecarga incluida', bucle y acceso real.
La diferencia entre el tiempo 'desnudo' y el tiempo 'sobrecargado excluido' me da una indicación del tiempo de 'acceso a la estructura'.
Pero, ¿qué tan preciso es este momento? Durante la prueba, las ventanas harán algo de tiempo para cortar shure. No tengo información sobre la división del tiempo, pero supongo que se distribuye uniformemente durante la prueba y en el orden de decenas de ms, lo que significa que la precisión del tiempo debe ser del orden de +/- 100 ms aproximadamente. ¿Una estimación un poco aproximada? De todos modos, una fuente de un error sistemático de medición.
Además, las pruebas se realizaron en modo 'Depuración' sin optimización. De lo contrario, el compilador podría cambiar el código de prueba real.
Entonces, obtengo dos resultados, uno para una constante, marcado '(c)', y otro para el acceso marcado '(n)' y la diferencia 'dt' me dice cuánto tiempo lleva el acceso real.
Y estos son los resultados:
Con mejores estimaciones sobre los errores de tiempo (¿cómo eliminar el error de medición sistemática debido a la división del tiempo?) Se podría decir más sobre los resultados.
Parece que List / foreach tiene el acceso más rápido, pero la sobrecarga lo está matando.
La diferencia entre List / for y List / foreach es extraña. Tal vez se trata de cobrar?
Además, para acceder a una matriz, no importa si usa un
for
bucle o unforeach
bucle. Los resultados de tiempo y su precisión hacen que los resultados sean 'comparables'.Usar un diccionario es, con mucho, el más lento, solo lo consideré porque en el lado izquierdo (el indexador) tengo una lista escasa de enteros y no un rango como se usa en estas pruebas.
Aquí está el código de prueba modificado.
fuente
En algunas pruebas breves, he encontrado que una combinación de ambas es mejor en lo que llamaría Matemáticas razonablemente intensivas:
Tipo:
List<double[]>
Tipo:
List<List<double>>
Tipo:
double[rows * columns]
Ejecutando el Código:
¡Ojalá tuviéramos algunas clases de matriz acelerada por hardware de primer nivel como lo ha hecho el equipo .NET con la
System.Numerics.Vectors
clase!¡C # podría ser el mejor lenguaje ML con un poco más de trabajo en esta área!
fuente