usa recorrer que para loop for array c# .net performance for-loop

c# - recorrer - En.NET, ¿qué bucle se ejecuta más rápido, ''for'' o ''foreach''?



recorrer array c# foreach (30)

"¿Hay algún argumento que pueda usar para ayudarme a convencerlo de que el bucle for es aceptable para usar?"

No, si su jefe está microgestionando al nivel de decirle qué construcciones de lenguaje de programación debe usar, realmente no hay nada que pueda decir. Lo siento.

En C # / VB.NET / .NET, ¿qué bucle se ejecuta más rápido, for o for ?

Desde que leí que un bucle for funciona más rápido que un bucle foreach hace mucho tiempo, asumí que era válido para todas las colecciones, colecciones genéricas, todas las matrices, etc.

Revisé Google y encontré algunos artículos, pero la mayoría de ellos no son concluyentes (leer comentarios sobre los artículos) y están abiertos.

Lo que sería ideal es tener cada escenario en la lista y la mejor solución para el mismo.

Por ejemplo (solo un ejemplo de cómo debería ser):

  1. para iterar una serie de más de 1000 cadenas, for es mejor que foreach
  2. para iterar sobre cadenas IList (no genéricas) - foreach es mejor que for

Algunas referencias encontradas en la web para el mismo:

  1. Gran artículo original de Emmanuel Schanzer.
  2. CodeProject FOREACH Vs. PARA
  3. Blog - foreach o no foreach , esa es la pregunta
  4. Foro de ASP.NET - NET 1.1 C # for vs foreach

[Editar]

Aparte del aspecto de la legibilidad, estoy realmente interesado en hechos y cifras. Hay aplicaciones en las que la última milla de optimización del rendimiento exprimido no importa.


A menos que esté en un proceso de optimización de velocidad específico, yo diría que use el método que produzca el código más fácil de leer y mantener.

Si ya se ha configurado un iterador, como con una de las clases de colección, entonces foreach es una buena opción fácil. Y si lo que estás iterando es un rango de enteros, entonces probablemente sea más limpio.


Cada construcción de lenguaje tiene un tiempo y un lugar apropiados para su uso. Existe una razón por la cual el lenguaje C # tiene cuatro declaraciones de iteración separadas: cada una está ahí para un propósito específico y tiene un uso apropiado.

Recomiendo sentarse con su jefe y tratar de explicar racionalmente por qué un bucle for tiene un propósito. Hay ocasiones en que un bloque de iteración describe más claramente un algoritmo que una iteración de foreach . Cuando esto es cierto, es apropiado usarlos.

También le señalaría a su jefe: el rendimiento no es, y no debería ser un problema de ninguna manera práctica, es más una cuestión de expresión el algoritmo de una manera sucinta, significativa y fácil de mantener. Las microoptimizaciones como esta no alcanzan el punto de la optimización del rendimiento, ya que cualquier beneficio real del rendimiento provendrá del rediseño y refactorización algorítmica, no de la reestructuración del bucle.

Si, luego de una discusión racional, todavía existe este punto de vista autoritario, depende de usted cómo proceder. Personalmente, no me sentiría feliz trabajando en un entorno donde se desalienta el pensamiento racional, y consideraría cambiarme a otro cargo bajo un empleador diferente. Sin embargo, recomiendo enfáticamente la discusión antes de enojarse, puede que haya un simple malentendido.


En la mayoría de los casos realmente no hay diferencia.

Normalmente, siempre tiene que usar foreach cuando no tiene un índice numérico explícito, y siempre tiene que usar para cuando en realidad no tiene una colección iterable (por ejemplo, iterar sobre una cuadrícula de matriz bidimensional en un triángulo superior) . Hay algunos casos donde tienes una opción.

Se podría argumentar que para los bucles puede ser un poco más difícil de mantener si los números mágicos comienzan a aparecer en el código. Debería estar en lo cierto al estar molesto por no poder usar un bucle for y tener que crear una colección o usar un lambda para construir una subcolección en su lugar solo porque los bucles han sido prohibidos.


En los casos en los que trabaja con una colección de objetos, foreach es mejor, pero si incrementa un número, un bucle for es mejor.

Tenga en cuenta que en el último caso, podría hacer algo como:

foreach (int i in Enumerable.Range(1, 10))...

Pero ciertamente no tiene un mejor desempeño, en realidad tiene un peor desempeño en comparación con un for .


Encontré el bucle foreach que itera a través de una List más rápido . Ver los resultados de mi prueba a continuación. En el código que aparece a continuación, itero una array de tamaño 100, 10000 y 100000 por separado utilizando for y foreach loop para medir el tiempo.

private static void MeasureTime() { var array = new int[10000]; var list = array.ToList(); Console.WriteLine("Array size: {0}", array.Length); Console.WriteLine("Array For loop ......"); var stopWatch = Stopwatch.StartNew(); for (int i = 0; i < array.Length; i++) { Thread.Sleep(1); } stopWatch.Stop(); Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds); Console.WriteLine(" "); Console.WriteLine("Array Foreach loop ......"); var stopWatch1 = Stopwatch.StartNew(); foreach (var item in array) { Thread.Sleep(1); } stopWatch1.Stop(); Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds); Console.WriteLine(" "); Console.WriteLine("List For loop ......"); var stopWatch2 = Stopwatch.StartNew(); for (int i = 0; i < list.Count; i++) { Thread.Sleep(1); } stopWatch2.Stop(); Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds); Console.WriteLine(" "); Console.WriteLine("List Foreach loop ......"); var stopWatch3 = Stopwatch.StartNew(); foreach (var item in list) { Thread.Sleep(1); } stopWatch3.Stop(); Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds); }

ACTUALIZADO

Después de la sugerencia de @jgauffin, utilicé el código de @johnskeet y descubrí que el bucle for con array es más rápido que el siguiente,

  • Foreach loop con array.
  • Para bucle con lista.
  • Foreach loop con lista.

Ver los resultados de mi prueba y el código a continuación,

private static void MeasureNewTime() { var data = new double[Size]; var rng = new Random(); for (int i = 0; i < data.Length; i++) { data[i] = rng.NextDouble(); } Console.WriteLine("Lenght of array: {0}", data.Length); Console.WriteLine("No. of iteration: {0}", Iterations); Console.WriteLine(" "); double correctSum = data.Sum(); Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { double sum = 0; for (int j = 0; j < data.Length; j++) { sum += data[j]; } if (Math.Abs(sum - correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); for (var i = 0; i < Iterations; i++) { double sum = 0; foreach (double d in data) { sum += d; } if (Math.Abs(sum - correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds); Console.WriteLine(" "); var dataList = data.ToList(); sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { double sum = 0; for (int j = 0; j < dataList.Count; j++) { sum += data[j]; } if (Math.Abs(sum - correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { double sum = 0; foreach (double d in dataList) { sum += d; } if (Math.Abs(sum - correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds); }


Es lo que haces dentro del bucle lo que afecta el rendimiento, no la construcción del bucle real (suponiendo que tu caso no sea trivial).


Es poco probable que exista una gran diferencia de rendimiento entre los dos. Como siempre, cuando nos enfrentamos a un "¿cuál es más rápido?" Pregunta, siempre debes pensar "Puedo medir esto".

Escriba dos bucles que hagan lo mismo en el cuerpo del bucle, ejecute y cronometre ambos, y vea cuál es la diferencia en la velocidad. Haz esto con un cuerpo casi vacío y un cuerpo de bucle similar a lo que realmente estarás haciendo. Inténtelo también con el tipo de colección que está utilizando, ya que diferentes tipos de colecciones pueden tener diferentes características de rendimiento.


Esto debería salvarte:

public IEnumerator<int> For(int start, int end, int step) { int n = start; while (n <= end) { yield n; n += step; } }

Utilizar:

foreach (int n in For(1, 200, 4)) { Console.WriteLine(n); }

Para mayor ganancia, puede tomar tres delegados como parámetros.


Esto es ridículo. No hay ninguna razón convincente para prohibir el bucle for, el rendimiento u otro.

Consulte el blog de Jon Skeet para obtener una referencia de rendimiento y otros argumentos.


Esto tiene las mismas dos respuestas que la mayoría de las preguntas "que es más rápido":

1) Si no se mide, no se sabe.

2) (Porque ...) Depende.

Depende de lo costoso que sea el método "MoveNext ()", en relación con lo costoso que sea el método "this [int index]", para el tipo (o tipos) de IEnumerable sobre los que se repetirá la iteración.

La palabra clave "foreach" es una forma abreviada de una serie de operaciones: llama a GetEnumerator () una vez en IEnumerable, llama a MoveNext () una vez por iteración, realiza algunas comprobaciones de tipo, etc. Lo más probable es que afecte las mediciones de rendimiento es el costo de MoveNext (), ya que se invoca O (N) veces. Tal vez sea barato, pero tal vez no lo sea.

La palabra clave "para" parece más predecible, pero en la mayoría de los "bucles" encontrará algo como "colección [índice]". Esto parece una simple operación de indexación de matrices, pero en realidad es una llamada de método, cuyo costo depende completamente de la naturaleza de la colección sobre la que está iterando. Probablemente sea barato, pero tal vez no lo sea.

Si la estructura subyacente de la colección es esencialmente una lista vinculada, MoveNext es muy barato, pero el indexador puede tener un costo O (N), lo que hace que el costo real de un bucle "for" O (N * N).


Hay muy buenas razones para preferir bucles foreach sobre bucles. Si puedes usar un bucle foreach , tu jefe tiene razón en que debes hacerlo.

Sin embargo, no todas las iteraciones simplemente pasan por una lista en orden una por una. Si él lo está prohibiendo , sí, eso está mal.

Si yo fuera tú, lo que haría sería convertir todo lo natural de tus bucles en recursión . Eso le enseñaría, y también es un buen ejercicio mental para ti.


Jeffrey Richter en TechEd 2005:

"He aprendido a lo largo de los años que el compilador de C # es básicamente un mentiroso para mí". .. "Se trata de muchas cosas". .. "Al igual que cuando haces un bucle foreach ..." .. "... esa es una pequeña línea de código que escribes, pero lo que escupe el compilador de C # para hacer eso es fenomenal. Emite un intente / finalmente bloquee allí, dentro del bloque finalmente convierte su variable en una interfaz IDisposable, y si el lanzamiento tiene éxito, llama al método Dispose, dentro del bucle llama a la propiedad Actual y al método MoveNext repetidamente dentro del bucle, se están creando objetos debajo de las cubiertas. Mucha gente usa foreach porque es muy fácil de codificar, muy fácil de hacer ... ".." foreach no es muy bueno en términos de rendimiento, si iteró sobre una colección en lugar de usar el cuadrado La notación de corchetes, solo haciendo índice, es mucho más rápido, y no crea ningún objeto en el montón ... "

Webcast a pedido: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US



Las diferencias en la velocidad en un bucle for y foreach son pequeñas cuando se recorre estructuras comunes como matrices, listas, etc., y hacer una consulta LINQ sobre la colección es casi siempre un poco más lento, ¡aunque es mejor escribir! Como dijeron los otros carteles, opte por la expresividad en lugar de un milisegundo de rendimiento adicional.

Lo que no se ha dicho hasta ahora es que cuando se compila un bucle foreach , el compilador lo optimiza en función de la colección sobre la que está iterando. Eso significa que cuando no estás seguro de qué bucle utilizar, debes usar el bucle foreach : generará el mejor bucle para ti cuando se compile. También es más legible.

Otra ventaja clave con el bucle foreach es que si la implementación de su colección cambia (de una array int a una List<int> por ejemplo), entonces su bucle foreach no requerirá ningún cambio de código:

foreach (int i in myCollection)

Lo anterior es el mismo, sin importar de qué tipo sea su colección, mientras que en su bucle for , lo siguiente no se generará si cambió myCollection de una array a una List :

for (int i = 0; i < myCollection.Length, i++)


Los dos correrán casi exactamente de la misma manera. Escribe un código para usar ambos, luego muéstrale el IL. Debe mostrar cálculos comparables, lo que significa que no hay diferencia en el rendimiento.


Mi conjetura es que probablemente no será significativo en el 99% de los casos, entonces ¿por qué elegiría el más rápido en lugar del más apropiado (como en el más fácil de entender / mantener)?


Patrick Smacchia hizo un blog sobre este último mes, con las siguientes conclusiones:

  • los bucles en la Lista son un poco más de dos veces más baratos que los bucles de cada lista.
  • El bucle en la matriz es aproximadamente 2 veces más barato que el bucle en la Lista.
  • Como consecuencia, el uso de bucles en la matriz es 5 veces más barato que el uso de bucles en la Lista utilizando foreach (que creo que es lo que todos hacemos).

Primero, un reclamo contrario a la respuesta de Dmitry . Para las matrices, el compilador de C # emite en gran parte el mismo código para foreach que para un bucle equivalente. Eso explica por qué para este punto de referencia, los resultados son básicamente los mismos:

using System; using System.Diagnostics; using System.Linq; class Test { const int Size = 1000000; const int Iterations = 10000; static void Main() { double[] data = new double[Size]; Random rng = new Random(); for (int i=0; i < data.Length; i++) { data[i] = rng.NextDouble(); } double correctSum = data.Sum(); Stopwatch sw = Stopwatch.StartNew(); for (int i=0; i < Iterations; i++) { double sum = 0; for (int j=0; j < data.Length; j++) { sum += data[j]; } if (Math.Abs(sum-correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); for (int i=0; i < Iterations; i++) { double sum = 0; foreach (double d in data) { sum += d; } if (Math.Abs(sum-correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds); } }

Resultados:

For loop: 16638 Foreach loop: 16529

A continuación, valide que el punto de Greg sobre el tipo de colección es importante: cambie la matriz a una List<double> de lo anterior, y obtendrá resultados radicalmente diferentes. No solo es significativamente más lento en general, sino que cada vez se vuelve más lento que el acceso por índice. Habiendo dicho eso, casi siempre preferiría foreach para un bucle for donde hace que el código sea más simple, porque la legibilidad es casi siempre importante, mientras que la micro-optimización rara vez lo es.


Probablemente depende del tipo de colección que está enumerando y la implementación de su indexador. En general, sin embargo, usar foreach probablemente sea un mejor enfoque.

Además, funcionará con cualquier IEnumerable , no solo con los indexadores.


Realmente atornille con su cabeza y busque un cierre de IQueryable .foreach en su lugar:

myList.ForEach (c => Console.WriteLine (c.ToString ());

Jaja


Siempre estará cerca. Para una matriz, a veces es un poco más rápido, pero foreach es más expresivo y ofrece LINQ, etc. En general, quédese con foreach .

Además, foreach puede optimizarse en algunos escenarios. Por ejemplo, una lista enlazada puede ser terrible por el indexador, pero puede ser rápida por cada persona. En realidad, el LinkedList<T> estándar LinkedList<T> ni siquiera ofrece un indexador por este motivo.


Siempre que haya argumentos sobre el rendimiento, solo tiene que escribir una pequeña prueba para poder utilizar los resultados cuantitativos para respaldar su caso.

Use la clase StopWatch y repita algo millones de veces, para mayor precisión. (Esto podría ser difícil sin un bucle for):

using System.Diagnostics; //... Stopwatch sw = new Stopwatch() sw.Start() for(int i = 0; i < 1000000;i ++) { //do whatever it is you need to time } sw.Stop(); //print out sw.ElapsedMilliseconds

Los dedos cruzaron los resultados de este programa y muestran que la diferencia es insignificante, y usted también podría hacer lo que sea en el código más fácil de mantener.


Ya sea for es más rápido que foreach es realmente el punto. Dudo seriamente que elegir uno sobre el otro tenga un impacto significativo en su rendimiento.

La mejor manera de optimizar su aplicación es a través del perfil del código real. Eso señalará los métodos que representan la mayor cantidad de trabajo / tiempo. Optimiza esos primero. Si el rendimiento aún no es aceptable, repita el procedimiento.

Como regla general, recomendaría que se mantenga alejado de las micro optimizaciones, ya que rara vez producirán ganancias significativas. La única excepción es cuando se optimizan las rutas de acceso identificadas (es decir, si su perfil identifica algunos métodos altamente utilizados, puede tener sentido optimizarlos ampliamente).


for tiene una lógica más simple de implementar, por lo que es más rápido que foreach.


foreach bucles foreach demuestran una intención más específica que los bucles for .

El uso de un bucle foreach demuestra a cualquier persona que use su código que está planeando hacer algo a cada miembro de una colección, independientemente de su lugar en la colección. También muestra que no está modificando la colección original (y lanza una excepción si lo intenta).

La otra ventaja de foreach es que funciona en cualquier IEnumerable , donde solo tiene sentido para IList , donde cada elemento tiene un índice.

Sin embargo, si necesita usar el índice de un elemento, entonces, por supuesto, debería poder usar un bucle for . Pero si no necesita usar un índice, tener uno es simplemente saturar su código.

No hay implicaciones significativas en el rendimiento, que yo sepa. En algún momento en el futuro podría ser más fácil adaptar el código usando foreach para ejecutarse en múltiples núcleos, pero eso no es algo de qué preocuparse ahora.


No esperaría que nadie encontrara una "enorme" diferencia de rendimiento entre los dos.

Supongo que la respuesta depende de si la colección a la que intenta acceder tiene una implementación de acceso de indexador más rápida o una implementación de acceso de IEnumerator más rápida. Como IEnumerator a menudo usa el indexador y solo tiene una copia de la posición actual del índice, esperaría que el acceso del enumerador sea al menos tan lento o más lento que el acceso directo al índice, pero no por mucho.

Por supuesto, esta respuesta no tiene en cuenta las optimizaciones que el compilador puede implementar.


Parece un poco extraño prohibir totalmente el uso de algo como un bucle for.

Hay un artículo interesante aquí que cubre una gran cantidad de las diferencias de rendimiento entre los dos bucles.

Yo diría que personalmente me parece que foreach es un poco más legible para los bucles, pero debería usar lo mejor para el trabajo en cuestión y no tener que escribir código muy largo para incluir un bucle foreach si un bucle for es más apropiado.


Lo probé hace un tiempo, con el resultado de que un forbucle es mucho más rápido que un foreachbucle. La causa es simple, el foreachbucle primero necesita crear una instancia IEnumeratorpara la colección.


Tenga en cuenta que for-loop y foreach-loop no siempre son equivalentes. Los enumeradores de la lista lanzarán una excepción si la lista cambia, pero no siempre obtendrá esa advertencia con un bucle normal para. Incluso podría obtener una excepción diferente si la lista cambia en el momento equivocado.