listas ejemplos colecciones arreglos .net performance arrays generics list

.net - ejemplos - colecciones en c#



Rendimiento de matrices vs. listas (13)

Aquí hay uno que usa Diccionarios, IEnumerable:

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; static class Program { static void Main() { List<int> list = new List<int>(6000000); for (int i = 0; i < 6000000; i++) { list.Add(i); } Console.WriteLine("Count: {0}", list.Count); int[] arr = list.ToArray(); IEnumerable<int> Ienumerable = list.ToArray(); Dictionary<int, bool> dict = list.ToDictionary(x => x, y => true); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } Console.WriteLine("Ienumerable/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } Console.WriteLine("Dict/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } watch.Stop(); Console.WriteLine("Ienumerable/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } watch.Stop(); Console.WriteLine("Dict/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } }

Digamos que necesita tener una lista / matriz de enteros que necesita repetir con frecuencia, y me refiero con mucha frecuencia. Las razones pueden variar, pero dicen que está en el corazón del ciclo 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, las listas de reclamaciones de documentación msdn usan una matriz internamente y deben funcionar igual de rápido (una mirada rápida con Reflector lo confirma). Nunca, hay algunos gastos generales involucrados.

¿Alguien realmente midió esto? iterar 6M veces a través de una lista toma el mismo tiempo que una matriz?


Como List <> usa matrices de manera interna, el rendimiento básico debería ser el mismo. Dos razones por las cuales la Lista puede ser un poco más lenta:

  • Para buscar un elemento en la lista, se llama a un método de lista, que hace la búsqueda en la matriz subyacente. Entonces necesitas una llamada de método adicional allí. Por otro lado, el compilador podría reconocer esto y optimizar la llamada "innecesaria".
  • El compilador puede hacer algunas optimizaciones especiales si conoce el tamaño de la matriz, que no puede hacer para una lista de longitud desconocida. Esto podría mejorar el rendimiento si solo tiene algunos elementos en su lista.

Para verificar si hace alguna diferencia para usted, probablemente sea mejor ajustar las funciones de tiempo publicadas a una lista del tamaño que planea usar y ver cómo son los resultados para su caso especial.


Como tenía una pregunta similar, esto me ayudó a comenzar 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''

La prueba realizada por Marc Gravell muestra mucho, pero no exactamente el tiempo de acceso. Su sincronización incluye el bucle sobre las listas 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órica.

Primero, hago una prueba usando una constante, lo que me da un cierto tiempo que incluye el ciclo. Esta es una sincronización ''simple'', excluyendo el acceso real. Luego realizo una prueba para acceder a la estructura del tema, esto me da el tiempo y el ''overhead incluido'', el bucle y el acceso real.

La diferencia entre el tiempo ''bare'' y el tiempo ''overhead indluded'' me da una indicación del tiempo de ''acceso a la estructura''.

Pero, ¿qué tan exacto es este momento? Durante la prueba, las ventanas harán un corte de tiempo para shure. No tengo información sobre el tiempo de corte, pero supongo que se distribuye de manera uniforme durante la prueba y en el orden de decenas de mseg, lo que significa que la precisión para el tiempo debería ser del orden de +/- 100 mseg o más. ¿Una estimación aproximada? De todos modos, una fuente de un error de reparación sistemático.

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:

Dictionary(c)/for: 1205ms (600000000) Dictionary(n)/for: 8046ms (589725196) dt = 6841 List(c)/for: 1186ms (1189725196) List(n)/for: 2475ms (1779450392) dt = 1289 Array(c)/for: 1019ms (600000000) Array(n)/for: 1266ms (589725196) dt = 247 Dictionary[key](c)/foreach: 2738ms (600000000) Dictionary[key](n)/foreach: 10017ms (589725196) dt = 7279 List(c)/foreach: 2480ms (600000000) List(n)/foreach: 2658ms (589725196) dt = 178 Array(c)/foreach: 1300ms (600000000) Array(n)/foreach: 1592ms (589725196) dt = 292 dt +/-.1 sec for foreach Dictionary 6.8 7.3 List 1.3 0.2 Array 0.2 0.3 Same test, different system: dt +/- .1 sec for foreach Dictionary 14.4 12.0 List 1.7 0.1 Array 0.5 0.7

Con mejores estimaciones de los errores de temporización (¿cómo eliminar el error de medición sistemático debido a la división temporal?) 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 sorprendente. Tal vez algún cambio está involucrado?

Además, para acceder a una matriz, no importa si usa un bucle for o un bucle foreach . Los resultados de sincronización y su precisión hacen que los resultados sean ''comparables''.

Usar un diccionario es de lejos el más lento, solo lo consideré porque en el lado izquierdo (el indexador) tengo una lista dispersa de enteros y no un rango como se usa en estas pruebas.

Aquí está el código de prueba modificado.

Dictionary<int, int> dict = new Dictionary<int, int>(6000000); List<int> list = new List<int>(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { int n = rand.Next(5000); dict.Add(i, n); list.Add(n); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += 1; // dict[i]; } } watch.Stop(); long c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += dict[i]; } } watch.Stop(); long n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += 1; // list[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/for: {0}ms ({1})", c_dt, chk); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += 1; // arr[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += 1; // dict[i]; ; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += dict[i]; ; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt);


Creo que el rendimiento será bastante similar. La sobrecarga que implica usar 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.

Supongamos que tiene una Lista con una Capacidad de 10, luego la Lista aumentará su capacidad una vez que desee agregar el 11 ° elemento. Puede disminuir el impacto en el rendimiento al inicializar la Capacidad de la lista para la cantidad de elementos que contendrá.

Pero, para descubrir si iterar sobre una Lista es tan rápido como iterar sobre una matriz, ¿por qué no lo comparas?

int numberOfElements = 6000000; List<int> theList = new List<int> (numberOfElements); int[] theArray = new int[numberOfElements]; for( int i = 0; i < numberOfElements; i++ ) { theList.Add (i); theArray[i] = i; } Stopwatch chrono = new Stopwatch (); chrono.Start (); int j; for( int i = 0; i < numberOfElements; i++ ) { j = theList[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the List took {0} msec", chrono.ElapsedMilliseconds)); chrono.Reset(); chrono.Start(); for( int i = 0; i < numberOfElements; i++ ) { j = theArray[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the array took {0} msec", chrono.ElapsedMilliseconds)); Console.ReadLine();

En mi sistema; iterar sobre la matriz tomó 33msec; iterar sobre la lista tomó 66msec.

Para ser honesto, no esperaba que la variación fuera tan grande. Entonces, puse mi iteración en un bucle: ahora, ejecuto ambas iteraciones 1000 veces. Los resultados son:

iterar la Lista tomó 67146 mseg iterando la matriz tomó 40821 mseg

Ahora, la variación ya no es tan grande, pero aún así ...

Por lo tanto, he iniciado .NET Reflector y el getter del indexador de la clase List, se ve así:

public T get_Item(int index) { if (index >= this._size) { ThrowHelper.ThrowArgumentOutOfRangeException(); } return this._items[index]; }

Como puede ver, cuando usa el indexador de la Lista, la Lista realiza una comprobación de si no está saliendo de los límites de la matriz interna. Este cheque adicional tiene un costo.


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.


En algunas pruebas breves, encontré una combinación de los dos para ser mejor en lo que yo llamaría Matemáticas razonablemente intensivas:

Tipo: List<double[]>

Hora: 00: 00: 05.1861300

Tipo: List<List<double>>

Hora: 00: 00: 05.7941351

Tipo: double[rows * columns]

Hora: 00: 00: 06.0547118

Ejecutando el código:

int rows = 10000; int columns = 10000; IMatrix Matrix = new IMatrix(rows, columns); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] = Math.E; for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] *= -Math.Log(Math.E); stopwatch.Stop(); TimeSpan ts = stopwatch.Elapsed; Console.WriteLine(ts.ToString());

¡Ojalá tuviéramos algunas clases de Matriz Acelerada de Matriz de primera clase como las que el Equipo .NET ha hecho con la Clase System.Numerics.Vectors !

C # podría ser el mejor lenguaje ML con un poco más de trabajo en esta área!


Las mediciones son agradables, pero obtendrás resultados significativamente diferentes dependiendo de lo que estés haciendo exactamente en tu bucle interno. Mida su propia situación. Si está utilizando multi-threading, eso solo es una actividad no trivial.


Me preocupaba que los Benchmarks publicados en otras respuestas aún dejaran espacio para que el compilador optimice, elimine o fusione bucles, así que escribí uno que:

  • Utiliza entradas impredecibles (al azar)
  • Ejecuta un cálculo con el resultado impreso en la consola
  • Modifica los datos de entrada cada repetición

El resultado es que una matriz directa tiene un rendimiento 250% mejor que un acceso a una matriz envuelta en un IList:

  • 1 mil millones de accesos de matriz: 4000 ms
  • 1 mil millones de accesos a la lista: 10000 ms
  • 100 millones de accesos a la matriz: 350 ms
  • 100 millones de accesos a la lista: 1000 ms

Aquí está el código:

static void Main(string[] args) { const int TestPointCount = 1000000; const int RepetitionCount = 1000; Stopwatch arrayTimer = new Stopwatch(); Stopwatch listTimer = new Stopwatch(); Point2[] points = new Point2[TestPointCount]; var random = new Random(); for (int index = 0; index < TestPointCount; ++index) { points[index].X = random.NextDouble(); points[index].Y = random.NextDouble(); } for (int repetition = 0; repetition <= RepetitionCount; ++repetition) { if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Start(); } doWorkOnArray(points); if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Stop(); } if (repetition > 0) { // first repetition is for cache warmup listTimer.Start(); } doWorkOnList(points); if (repetition > 0) { // first repetition is for cache warmup listTimer.Stop(); } } Console.WriteLine("Ignore this: " + points[0].X + points[0].Y); Console.WriteLine( string.Format( "{0} accesses on array took {1} ms", RepetitionCount * TestPointCount, arrayTimer.ElapsedMilliseconds ) ); Console.WriteLine( string.Format( "{0} accesses on list took {1} ms", RepetitionCount * TestPointCount, listTimer.ElapsedMilliseconds ) ); } private static void doWorkOnArray(Point2[] points) { var random = new Random(); int pointCount = points.Length; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can''t eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; } private static void doWorkOnList(IList<Point2> points) { var random = new Random(); int pointCount = points.Count; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can''t eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; }


Muy fácil de medir ...

En una pequeña cantidad de código de procesamiento estricto donde sé que la longitud es fija , utilizo arreglos para ese pequeño poquito de micro-optimización; las matrices pueden ser marginalmente más rápidas si usa el indizador / para formulario, pero 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ás leyendo todos los datos; un diccionario sería más rápido para las 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 el error)

List/for: 1971ms (589725196) Array/for: 1864ms (589725196) List/foreach: 3054ms (589725196) Array/foreach: 1860ms (589725196)

basado en la plataforma de prueba:

using System; using System.Collections.Generic; using System.Diagnostics; static class Program { static void Main() { List<int> list = new List<int>(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next(5000)); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } }


No intente agregar capacidad aumentando la cantidad de elementos.

Actuación

List For Add: 1ms Array For Add: 2397ms

Stopwatch watch; #region --> List For Add <-- List<int> intList = new List<int>(); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 60000; rpt++) { intList.Add(rand.Next()); } watch.Stop(); Console.WriteLine("List For Add: {0}ms", watch.ElapsedMilliseconds); #endregion #region --> Array For Add <-- int[] intArray = new int[0]; watch = Stopwatch.StartNew(); int sira = 0; for (int rpt = 0; rpt < 60000; rpt++) { sira += 1; Array.Resize(ref intArray, intArray.Length + 1); intArray[rpt] = rand.Next(); } watch.Stop(); Console.WriteLine("Array For Add: {0}ms", watch.ElapsedMilliseconds); #endregion


Respuesta corta:

Una respuesta más detallada la encontrará en el siguiente enlace: https://.com/a/29263914/4423545


[ Ver también esta pregunta ]

He modificado la respuesta de Marc para usar números aleatorios reales y hacer el mismo trabajo en todos los casos.

Resultados:

for foreach Array : 1575ms 1575ms (+0%) List : 1630ms 2627ms (+61%) (+3%) (+67%) (Checksum: -1000038876)

Compilado como versión bajo VS 2008 SP1. Se ejecuta sin depuración en un [email protected], .NET 3.5 SP1.

Código:

class Program { static void Main(string[] args) { List<int> list = new List<int>(6000000); Random rand = new Random(1); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next()); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = arr.Length; for (int i = 0; i < len; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.WriteLine(); Console.ReadLine(); } }


si solo está obteniendo un valor único de cualquiera de los dos (no en un bucle), entonces los dos marcan la comprobación de los límites (el código administrado lo recuerda) 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 para (int int i = 0; i <x. [Longitud / recuento]; i ++), la diferencia clave es la siguiente:

  • Formación:
    • se elimina la comprobación de límites
  • Liza
    • se realiza la verificación de límites

Si usa foreach, la diferencia clave es la siguiente:

  • Formación:
    • no se asigna ningún objeto para administrar la iteración
    • se elimina la comprobación de límites
  • Lista a través de una variable conocida como Lista.
    • la variable de gestión de iteración está asignada a la pila
    • se realiza la verificación de límites
  • Lista a través de una variable conocida como IList.
    • la variable de gestión de iteración se asigna en el montón
    • se realiza la comprobación de límites; los valores de las Listas no se pueden alterar durante el foreach, mientras que los de la matriz pueden serlo.

La comprobación de límites a menudo no es gran cosa (especialmente si está en una CPU con una predicción profunda de oleoductos y bifurcaciones, la norma para la mayoría de estos días) pero solo su propio perfil le puede decir si eso es un problema. Si está en partes de su código donde está evitando asignaciones de montón (buenos ejemplos son bibliotecas o en implementaciones de código hash), entonces asegurarse de que la variable se tipee como List not IList evitará esa trampa. Como siempre, perfil si es importante.