En C # / VB.NET / .NET, ¿qué ciclo se ejecuta más rápido for
o foreach
?
Desde que leí que un for
bucle funciona más rápido que un foreach
bucle hace mucho tiempo, supuse que era cierto para todas las colecciones, colecciones genéricas, todas las matrices, etc.
Recorrí Google y encontré algunos artículos, pero la mayoría de ellos no son concluyentes (lea los comentarios sobre los artículos) y están abiertos.
Lo ideal sería 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):
- para iterar una matriz de más de 1000 cadenas,
for
es mejor queforeach
- para iterar sobre
IList
cadenas (no genéricas):foreach
es mejor quefor
Algunas referencias encontradas en la web para lo mismo:
- Gran artículo original de Emmanuel Schanzer
- CodeProject FOREACH Vs. PARA
- Blog: para
foreach
o noforeach
, esa es la pregunta - Foro ASP.NET - NET 1.1 C #
for
vsforeach
[Editar]
Además del aspecto de legibilidad, estoy realmente interesado en hechos y cifras. Hay aplicaciones en las que importa la última milla de optimización de rendimiento.
fuente
foreach
lugar defor
en C #. Si ve aquí respuestas que no tienen ningún sentido, es por eso. Culpe al moderador, no a las respuestas desafortunadas.Respuestas:
Patrick Smacchia escribió en su blog sobre este último mes, con las siguientes conclusiones:
fuente
foreach
que se necesita para recorrer una matrizfor
, ¿y lo llama insignificante? Ese tipo de diferencia de rendimiento puede ser importante para su aplicación, y puede que no, pero no lo descartaría sin más.foreach
.Primero, una contrademanda a la respuesta de Dmitry (ahora eliminada) . Para las matrices, el compilador de C # emite en gran medida el mismo código
foreach
que para unfor
bucle equivalente . Eso explica por qué para este punto de referencia, los resultados son básicamente los mismos:Resultados:
Luego, valide que el punto de Greg sobre el tipo de colección es importante: cambie la matriz a a
List<double>
en lo anterior y obtendrá resultados radicalmente diferentes. No solo es significativamente más lento en general, sino que foreach se vuelve significativamente más lento que acceder por índice. Dicho esto, todavía preferiría casi siempre foreach a un bucle for donde simplifica el código, porque la legibilidad es casi siempre importante, mientras que la micro-optimización rara vez lo es.fuente
List<T>
? ¿La legibilidad también triunfa sobre la microoptimización en ese caso?List<T>
matrices. Las excepciones sonchar[]
ybyte[]
que con mayor frecuencia se tratan como "fragmentos" de datos en lugar de colecciones normales.foreach
los bucles demuestran una intención más específica que losfor
bucles .El uso de un
foreach
bucle demuestra a cualquiera que use su código que planea 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
foreach
es que funciona en cualquieraIEnumerable
, dondefor
solo tiene sentidoIList
, donde cada elemento tiene un índice.Sin embargo, si necesita usar el índice de un elemento, entonces, por supuesto, debería poder usar un
for
bucle. Pero si no necesita usar un índice, tener uno es simplemente abarrotar su código.No hay implicaciones significativas de rendimiento hasta donde yo sé. En algún momento en el futuro, podría ser más fácil adaptar el código
foreach
para ejecutar en múltiples núcleos, pero eso no es algo de qué preocuparse en este momento.fuente
foreach
.foreach
no está en absoluto relacionado con la programación funcional. Es un paradigma totalmente imperativo de programación. Atribuyes mal las cosas que suceden en TPL y PLINQforeach
.foreach
como un equivalente de unwhile
bucle). Creo que sé a lo que @ctford se refiere. La biblioteca paralela de tareas permite que la colección subyacente proporcione elementos en un orden arbitrario (llamando.AsParallel
a un enumerable).foreach
no hace nada aquí y el cuerpo del bucle se ejecuta en un solo hilo . Lo único que está paralelo es la generación de la secuencia.foreach
y elfor
rendimiento de las listas normales es una fracción de segundo para iterar sobre millones de elementos, por lo que su problema ciertamente no estaba directamente relacionado con el rendimiento de cada uno, al menos no para unos pocos cientos de objetos. Suena como una implementación de enumerador rota en cualquier lista que estaba usando.Cada vez que hay argumentos sobre el rendimiento, solo necesita escribir una pequeña prueba para que pueda usar resultados cuantitativos para respaldar su caso.
Use la clase StopWatch y repita algo unos millones de veces, para mayor precisión. (Esto podría ser difícil sin un bucle for):
Los dedos cruzaron los resultados de este programa que muestran que la diferencia es insignificante, y que bien podría hacer lo que resulte en el código más fácil de mantener
fuente
Siempre estará cerca. Para una matriz, a veces
for
es un poco más rápido, peroforeach
es más expresivo y ofrece LINQ, etc. En general, quédese conforeach
.Además,
foreach
puede optimizarse en algunos escenarios. Por ejemplo, una lista vinculada puede ser terrible por indexador, pero puede ser rápida porforeach
. En realidad, el estándarLinkedList<T>
ni siquiera ofrece un indexador por este motivo.fuente
LinkedList<T>
es más delgado queList<T>
? Y si siempre voy a usarforeach
(en lugar defor
), ¿es mejor usarLinkedList<T>
?List<T>
). Es más que es más barato insertar / eliminar .Supongo 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 el más fácil de entender / mantener)?
fuente
Es poco probable que haya 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 velocidad. Haga esto con un cuerpo casi vacío y un cuerpo de bucle similar a lo que realmente hará. También pruébelo con el tipo de colección que está utilizando, porque los diferentes tipos de colecciones pueden tener diferentes características de rendimiento.
fuente
Hay muy buenas razones para preferir
foreach
bucles sobrefor
bucles. Si puede usar unforeach
bucle, su jefe tiene razón en que debería hacerlo.Sin embargo, no todas las iteraciones simplemente pasan por una lista en orden una por una. Si él está prohibiendo , sí, eso está mal.
Si yo fuera tú, lo que haría sería convertir todos tus bucles naturales en recursividad . Eso le enseñaría, y también es un buen ejercicio mental para ti.
fuente
for
bucles y losforeach
bucles en cuanto al rendimiento?Jeffrey Richter en TechEd 2005:
Webcast bajo demanda: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US
fuente
Esto es ridículo. No hay una razón convincente para prohibir el for-loop, el rendimiento inteligente u otro.
Vea el blog de Jon Skeet para un punto de referencia de rendimiento y otros argumentos.
fuente
En los casos en que trabaja con una colección de objetos,
foreach
es mejor, pero si incrementa un número, unfor
bucle es mejor.Tenga en cuenta que en el último caso, podría hacer algo como:
Pero ciertamente no funciona mejor, en realidad tiene un rendimiento peor en comparación con a
for
.fuente
Esto debería salvarte:
Utilizar:
Para una mayor victoria, puede tomar tres delegados como parámetros.
fuente
for
generalmente se escribe un bucle para excluir el final del rango (p0 <= i < 10
. Ej .).Parallel.For
también lo hace para mantenerlo fácilmente intercambiable con unfor
bucle común .puedes leer sobre esto en Deep .NET - parte 1 Iteración
cubre los resultados (sin la primera inicialización) desde el código fuente de .NET hasta el desmontaje.
por ejemplo: iteración de matriz con un bucle foreach:
y - enumerar iteración con foreach loop:
y los resultados finales:
fuente
Las diferencias de velocidad en a
for
- y a -foreach
loop son muy pequeñas cuando recorres estructuras comunes como matrices, listas, etc., y hacer unaLINQ
consulta sobre la colección es casi siempre un poco más lento, ¡aunque es mejor escribir! Como decían los otros carteles, busque expresividad en lugar de un milisegundo de rendimiento adicional.Lo que no se ha dicho hasta ahora es que cuando
foreach
se compila un bucle, el compilador lo optimiza en función de la colección sobre la que está iterando. Eso significa que cuando no esté seguro de qué bucle usar, debe usar elforeach
bucle: generará el mejor bucle para usted cuando se compile. También es más legible.Otra ventaja clave con el
foreach
bucle es que si la implementación de su colección cambia (de un intarray
a un,List<int>
por ejemplo), entonces suforeach
bucle no requerirá ningún cambio de código:Lo anterior es el mismo sin importar de qué tipo sea su colección, mientras que en su
for
ciclo, lo siguiente no se compilará si cambiamyCollection
dearray
a aList
:fuente
"¿Hay algún argumento que pueda usar para ayudarme a convencerlo de que el bucle for es aceptable?"
No, si tu jefe está microgestionando hasta el nivel de decirte qué construcciones de lenguaje de programación usar, realmente no hay nada que puedas decir. Lo siento.
fuente
Probablemente depende del tipo de colección que esté enumerando y la implementación de su indexador. Sin embargo, en general,
foreach
es probable que el uso sea un mejor enfoque.Además, funcionará con cualquiera
IEnumerable
, no solo con indexadores.fuente
Tiene las mismas dos respuestas que la mayoría de las preguntas "que es más rápido":
1) Si no mides, no lo sabes.
2) (Porque ...) Depende.
Depende de cuán costoso sea el método "MoveNext ()", en relación con lo costoso que es el método "this [int index]", para el tipo (o tipos) de IEnumerable sobre el que iterará.
La palabra clave "foreach" es la abreviatura 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 para impactar las mediciones de rendimiento es el costo de MoveNext () ya que se invoca O (N) veces. Quizás sea barato, pero quizás no lo sea.
La palabra clave "for" parece más predecible, pero dentro de la mayoría de los bucles "for" encontrará algo así como "colección [índice]". Esto parece una simple operación de indexación de matriz, pero en realidad es una llamada a un 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).
fuente
Cada construcción de lenguaje tiene un momento y lugar apropiados para su uso. Hay 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
for
ciclo tiene un propósito. Hay momentos en que unfor
bloque de iteración describe más claramente un algoritmo que unaforeach
iteración. Cuando esto es cierto, es apropiado usarlos.También le dirí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 del algoritmo de una manera sucinta, significativa y sostenible. Las micro optimizaciones como esta pierden por completo el punto de la optimización del rendimiento, ya que cualquier beneficio real del rendimiento vendrá del rediseño algorítmico y la refactorización, no de la reestructuración en bucle.
Si, después de una discusión racional, todavía existe este punto de vista autoritario, depende de usted cómo proceder. Personalmente, no sería feliz trabajando en un entorno donde se desalienta el pensamiento racional, y consideraría mudarme a otro puesto bajo un empleador diferente. Sin embargo, recomiendo encarecidamente la discusión antes de enfadarse; puede que haya un simple malentendido.
fuente
Es lo que haces dentro del bucle lo que afecta el rendimiento, no la construcción de bucle real (suponiendo que tu caso no sea trivial).
fuente
Si
for
es más rápido de lo queforeach
realmente es, además del 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 mediante la creación de perfiles del código real. Eso determinará los métodos que representan la mayor parte del trabajo / tiempo. Optimizar esos primero. Si el rendimiento aún no es aceptable, repita el procedimiento.
Como regla general, recomendaría mantenerse alejado de las micro optimizaciones, ya que rara vez producirán ganancias significativas. La única excepción es cuando se optimizan las rutas activas identificadas (es decir, si su perfil identifica algunos métodos muy utilizados, puede tener sentido optimizarlos ampliamente).
fuente
for
es marginalmente más rápido queforeach
. Me opondría seriamente a esta declaración. Eso depende totalmente de la colección subyacente. Si una clase de lista vinculada proporciona un indexador con un parámetro entero, esperaría que el uso de unfor
bucle sea O (n ^ 2) mientras queforeach
se espera que sea O (n).for
y una búsqueda de indexador con el usoforeach
por sí mismo. Creo que la respuesta de @Brian Rasmussen es correcta que, aparte de cualquier uso con una colección,for
siempre será un poco más rápido queforeach
. Sin embargo,for
más una búsqueda de colección siempre será más lenta queforeach
por sí sola.for
declaración. Elfor
bucle simple con una variable de control de enteros no es comparable aforeach
, por lo que está fuera. Entiendo lo que @Brian quiere decir y es correcto como dices, pero la respuesta puede ser engañosa. Re: su último punto: no, en realidad,for
terminarList<T>
es aún más rápido queforeach
.Los dos correrán casi exactamente de la misma manera. Escriba un código para usar ambos, luego muéstrele el IL. Debe mostrar cálculos comparables, lo que significa que no hay diferencia en el rendimiento.
fuente
tiene una lógica más simple de implementar, por lo que es más rápido que foreach.
fuente
A menos que esté en un proceso de optimización de velocidad específico, diría que use el método que produzca el código más fácil de leer y mantener.
Si un iterador ya está configurado, como con una de las clases de colección, entonces el foreach es una buena opción fácil. Y si está iterando un rango entero, entonces probablemente sea más limpio.
fuente
Jeffrey Richter habló sobre la diferencia de rendimiento entre for y foreach en un podcast reciente: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317
fuente
En la mayoría de los casos, realmente no hay diferencia.
Por lo general, siempre tiene que usar foreach cuando no tiene un índice numérico explícito, y siempre tiene que usar para cuando realmente no tiene una colección iterable (por ejemplo, iterar sobre una cuadrícula de matriz bidimensional en un triángulo superior) . Hay algunos casos en los que tiene una opción.
Se podría argumentar que los bucles for pueden ser un poco más difíciles de mantener si los números mágicos comienzan a aparecer en el código. Debería tener razón al estar molesto por no poder usar un bucle for y tener que construir una colección o usar una lambda para construir una subcolección solo porque los bucles for han sido prohibidos.
fuente
Parece un poco extraño prohibir totalmente el uso de algo así como un bucle for.
Hay un artículo interesante aquí. que cubre una gran cantidad de las diferencias de rendimiento entre los dos bucles.
Personalmente, creo que foreach es un poco más legible para los bucles, pero debe usar lo mejor para el trabajo en cuestión y no tener que escribir un código extralargo para incluir un bucle foreach si un bucle for es más apropiado.
fuente
Encontré el
foreach
ciclo que itera a través de unList
más rápido . Vea los resultados de mi prueba a continuación. En el código de abajo I iterar unaarray
de tamaño 100, 10000 y 100000 por separado utilizandofor
yforeach
bucle para medir el tiempo.ACTUALIZADO
Después de la sugerencia de @jgauffin, utilicé el código de @johnskeet y descubrí que el
for
bucle conarray
es más rápido que el siguiente,Vea los resultados de mi prueba y el código a continuación,
fuente
Realmente puedes atornillar su cabeza e ir por un cierre IQueryable .foreach en su lugar:
fuente
myList.ForEach(Console.WriteLine)
.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 está intentando 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 contiene una copia de la posición actual del índice, esperaría que el acceso al enumerador sea al menos tan lento o más lento que el acceso directo al índice, pero no mucho.
Por supuesto, esta respuesta no tiene en cuenta las optimizaciones que el compilador puede implementar.
fuente
Tenga en cuenta que el bucle for y el bucle foreach no siempre son equivalentes. Los enumeradores de listas arrojarán una excepción si la lista cambia, pero no siempre obtendrá esa advertencia con un ciclo for normal. Incluso puede obtener una excepción diferente si la lista cambia en el momento equivocado.
fuente