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

Resuelto Binoj Antony asked hace 16 años • 41 respuestas

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

Desde que leí que un forbucle funciona más rápido que un foreachbucle hace mucho tiempo, asumí que era válido para todas las colecciones, generic collectionstodas arrays, etc.

Busqué en Google y encontré algunos artículos, pero la mayoría de ellos no son concluyentes (lea los comentarios de los artículos) y son abiertos.

Lo ideal sería tener cada escenario enumerado y la mejor solución para el mismo.

Por ejemplo (solo un ejemplo de como debería ser):

  1. para iterar más arrayde 1000 cadenas, fores mejor queforeach
  2. para iterar sobre IListcadenas (no genéricas) - foreaches mejor quefor

Algunas referencias encontradas en la web sobre el mismo:

  1. Gran artículo original antiguo de Emmanuel Schanzer
  2. CodeProject FOREACH vs. PARA
  3. Blog - Hacer foreacho no foreach, esa es la cuestión
  4. Foro ASP.NET - NET 1.1 C# forvs.foreach

[Editar]

Aparte del aspecto de legibilidad, estoy realmente interesado en hechos y cifras. Hay aplicaciones en las que el último kilómetro de optimización del rendimiento sí importa.

Binoj Antony avatar Dec 14 '08 02:12 Binoj Antony
Aceptado

Patrick Smacchia escribió en su blog sobre esto el mes pasado, con las siguientes conclusiones:

  • Los bucles for en List son un poco más de 2 veces más baratos que los bucles foreach en List.
  • Hacer un bucle en una matriz es aproximadamente 2 veces más barato que hacerlo en una lista.
  • Como consecuencia, hacer un bucle en una matriz usando for es 5 veces más barato que hacer un bucle en una Lista usando foreach (que creo que es lo que todos hacemos).
Ian Nelson avatar Dec 13 '2008 20:12 Ian Nelson

Primero, una contrademanda a la respuesta de Dmitry (ahora eliminada) . Para las matrices, el compilador de C# emite prácticamente el mismo código que foreachlo haría para un forbucle 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 el punto de Greg acerca de que el tipo de colección es importante: cambie la matriz a a List<double>en lo anterior y obtendrá resultados radicalmente diferentes. No sólo es significativamente más lento en general, sino que foreach se vuelve significativamente más lento que el acceso por índice. Dicho esto, casi siempre preferiría foreach a un bucle for que simplifica el código, porque la legibilidad casi siempre es importante, mientras que la microoptimización rara vez lo es.

Jon Skeet avatar Jan 23 '2009 08:01 Jon Skeet

foreachLos bucles demuestran una intención más específica que forlos bucles .

El uso de un foreachbucle le demuestra a cualquiera que use su código que está planeando hacer algo con cada miembro de una colección, independientemente de su lugar en la colección. También muestra que no estás modificando la colección original (y genera una excepción si lo intentas).

La otra ventaja foreaches que funciona en cualquiera IEnumerable, donde forsolo tiene sentido para IList, donde cada elemento en realidad tiene un índice.

Sin embargo, si necesita utilizar el índice de un elemento, entonces, por supuesto, se le debería permitir utilizar un forbucle. Pero si no necesita utilizar un índice, tener uno sólo saturará su código.

Hasta donde yo sé, no hay implicaciones significativas en el rendimiento. En algún momento en el futuro, podría ser más fácil adaptar el código para foreachejecutarlo en múltiples núcleos, pero eso no es algo de qué preocuparse en este momento.

ctford avatar Dec 22 '2009 15:12 ctford

Cada vez que haya discusiones sobre el rendimiento, sólo necesita escribir una pequeña prueba para poder utilizar resultados cuantitativos para respaldar su caso.

Utilice la clase StopWatch y repita algo unos millones de veces para mayor precisión. (Esto podría resultar 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

Cruzamos los dedos y los resultados de esto muestran que la diferencia es insignificante, y también podrías hacer lo que resulte en el código más fácil de mantener.

Rob Fonseca-Ensor avatar Dec 22 '2009 15:12 Rob Fonseca-Ensor