matrice - visual c# while




In.NET, quale loop gira più velocemente, 'for' o 'foreach'? (20)

In C # / VB.NET / .NET, quale loop gira più veloce, for o foreach ?

Da quando ho letto che un ciclo for funziona più velocemente di un ciclo foreach molto tempo fa, ho pensato che fosse vero per tutte le collezioni, collezioni generiche, tutti gli array, ecc.

Ho setacciato Google e ho trovato alcuni articoli, ma la maggior parte di questi sono inconcludenti (leggi i commenti sugli articoli) e open ended.

Quale sarebbe l'ideale è avere ogni scenario elencato e la soluzione migliore per lo stesso.

Ad esempio (solo un esempio di come dovrebbe essere):

  1. per iterare una serie di oltre 1000 stringhe - for è meglio di foreach
  2. per iterare su stringhe IList (non generiche) - foreach è meglio che for

Alcuni riferimenti trovati sul Web per lo stesso:

  1. Originale grande vecchio articolo di Emmanuel Schanzer
  2. CodeProject FOREACH vs. PER
  3. Blog - foreach o non foreach , questa è la domanda
  4. Forum ASP.NET - NET 1.1 C # for vs foreach

[Modificare]

A parte l'aspetto della leggibilità, sono davvero interessato a fatti e cifre. Esistono applicazioni in cui l'ultimo miglio dell'ottimizzazione delle prestazioni è schiacciato.


"Ci sono argomenti che potrei usare per aiutarmi a convincerlo che il ciclo for è accettabile da usare?"

No, se il tuo capo è micromanaging al livello di dirti quali costrutti di linguaggio di programmazione utilizzare, non c'è davvero nulla che tu possa dire. Scusate.


È ciò che fai all'interno del ciclo che influisce sulla perfomance, non sul reale costrutto ciclico (supponendo che il tuo caso non sia banale).


A meno che non ci si trovi in ​​uno specifico processo di ottimizzazione della velocità, direi utilizzare qualsiasi metodo produca il codice più semplice da leggere e gestire.

Se un iteratore è già impostato, come in una delle classi di raccolta, allora foreach è una buona opzione facile. E se si tratta di un intervallo intero che stai iterando, allora è probabilmente più pulito.


Ci sono ottime ragioni per preferire i cicli di foreach over for loop. Se puoi usare un ciclo foreach , il tuo capo ha ragione che dovresti.

Tuttavia, non ogni iterazione sta semplicemente passando per una lista in ordine uno per uno. Se sta vietando , sì è sbagliato.

Se fossi in te, quello che farei è trasformare tutti i tuoi cicli naturali in ricorsioni . Questo gli avrebbe insegnato, ed è anche un buon esercizio mentale per te.


I due funzioneranno quasi esattamente allo stesso modo. Scrivi un codice per usarli entrambi, quindi mostragli l'IL. Dovrebbe mostrare calcoli comparabili, il che significa nessuna differenza nelle prestazioni.


Innanzitutto, una contro-rivendicazione della risposta di Dmitry . Per gli array, il compilatore C # emette in gran parte lo stesso codice per foreach come farebbe per un ciclo equivalente. Questo spiega perché per questo benchmark i risultati sono sostanzialmente gli stessi:

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);
    }
}

risultati:

For loop: 16638
Foreach loop: 16529

Successivamente, convalida il punto di Greg sul fatto che il tipo di raccolta sia importante - cambia la matrice in una List<double> nella precedente, e ottieni risultati radicalmente diversi. Non solo è notevolmente più lento in generale, ma foreach diventa molto più lento dell'accesso per indice. Detto questo, preferirei quasi sempre foreach a un ciclo for in cui rende il codice più semplice - perché la leggibilità è quasi sempre importante, mentre raramente lo è la micro-ottimizzazione.


Jeffrey Richter su TechEd 2005:

"Sono venuto per imparare nel corso degli anni che il compilatore C # è fondamentalmente un bugiardo per me." .. "Si trova su molte cose." .. "Come quando fai un ciclo foreach ..." .. "... quella è una piccola riga di codice che scrivi, ma ciò che il compilatore C # sputa per farlo è fenomenale. prova / finalmente blocca lì dentro, dentro il blocco finally getta la tua variabile su un'interfaccia IDisposable, e se il cast supera lo chiama il metodo Dispose su di esso, all'interno del ciclo chiama ripetutamente la proprietà Current e il metodo MoveNext all'interno del loop, gli oggetti vengono creati sotto le copertine.Un sacco di persone usa foreach perché è molto facile da codificare, molto facile da fare .. ".." foreach non è molto buono in termini di prestazioni, se si esegue un'iterazione su una raccolta utilizzando invece la piazza notazione delle parentesi, basta fare index, è solo molto più veloce, e non crea nessun oggetto sull'heap ... "

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


La mia ipotesi è che probabilmente non sarà significativo nel 99% dei casi, quindi perché dovresti scegliere il più veloce anziché il più appropriato (come nel modo più semplice da capire / mantenere)?


Nei casi in cui si lavora con una collezione di oggetti, foreach è migliore, ma se si incrementa un numero, un ciclo for è migliore.

Nota che nell'ultimo caso potresti fare qualcosa del tipo:

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

Ma certamente non ha prestazioni migliori, in realtà ha prestazioni peggiori rispetto a un for .


Nella maggior parte dei casi non c'è davvero differenza.

In genere devi sempre usare foreach quando non hai un indice numerico esplicito, e devi sempre usarlo quando non hai effettivamente una collezione iterabile (ad esempio, iterando su una griglia di array bidimensionale in un triangolo superiore) . Ci sono alcuni casi in cui puoi scegliere.

Si potrebbe obiettare che per i loop può essere un po 'più difficile da mantenere se i numeri magici iniziano ad apparire nel codice. Dovresti avere ragione ad essere infastidito dal fatto di non essere in grado di utilizzare un ciclo for e di dover creare una raccolta o utilizzare un lambda per creare una sottoraccolta, semplicemente perché i loop sono stati bannati.


Ogni volta che ci sono argomenti sulle prestazioni, è sufficiente scrivere un piccolo test in modo da poter utilizzare risultati quantitativi per supportare il tuo caso.

Usa la classe StopWatch e ripeti qualcosa qualche milione di volte, per precisione. (Potrebbe essere difficile senza un ciclo 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

Le dita incrociate i risultati di questo spettacolo che la differenza è trascurabile, e si potrebbe anche solo fare qualsiasi risultato nel codice più gestibile


Patrick Smacchia ha scritto sul blog questo mese, con le seguenti conclusioni:

  • per i loop su List sono un po 'più di 2 volte meno costosi di quelli foreach su List.
  • Il ciclo su array è circa 2 volte più economico rispetto al loop su List.
  • Di conseguenza, il looping su array usando for è 5 volte più economico di un loop su List usando foreach (che credo sia quello che facciamo tutti).

Questo è ridicolo. Non vi è alcun motivo convincente per vietare il ciclo for, performance-saggio o altro.

Vedi il blog di Jon Skeet per un benchmark delle prestazioni e altri argomenti.


Questo dovrebbe salvarti:

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

Uso:

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

Per una maggiore vincita, puoi prendere tre delegati come parametri.


Sarà sempre vicino. Per un array, a volte for è leggermente più veloce, ma foreach è più espressivo e offre LINQ, ecc. In generale, attenersi a foreach .

Inoltre, foreach può essere ottimizzato in alcuni scenari. Ad esempio, un elenco collegato potrebbe essere terribile con l'indicizzatore, ma potrebbe essere rapido da parte di foreach . In realtà, lo standard LinkedList<T> non offre nemmeno un indicizzatore per questo motivo.


Se for è più veloce di foreach è davvero oltre il punto. Dubito seriamente che la scelta dell'uno sull'altro abbia un impatto significativo sulla tua performance.

Il modo migliore per ottimizzare la tua applicazione è attraverso la profilazione del codice reale. Ciò individuerà i metodi che rappresentano il maggior tempo di lavoro / tempo. Ottimizza quelli prima. Se le prestazioni non sono ancora accettabili, ripetere la procedura.

Come regola generale, consiglierei di stare lontano da micro ottimizzazioni poiché raramente produrranno guadagni significativi. L'unica eccezione è quando si ottimizzano i percorsi hot identificati (cioè se la propria profilazione identifica alcuni metodi altamente utilizzati, potrebbe essere sensato ottimizzarli in modo estensivo).


foreach cicli foreach dimostrano un intento più specifico rispetto for loop .

L'utilizzo di un ciclo foreach dimostra a chiunque utilizzi il codice che si prevede di fare qualcosa per ciascun membro di una raccolta indipendentemente dalla sua posizione nella raccolta. Mostra anche che non stai modificando la collezione originale (e lancia un'eccezione se provi a).

L'altro vantaggio di foreach è che funziona su qualsiasi oggetto IEnumerable , dove, come per IList , ha senso solo dove ogni elemento ha effettivamente un indice.

Tuttavia, se è necessario utilizzare l'indice di un elemento, ovviamente è necessario utilizzare un ciclo for . Ma se non hai bisogno di usare un indice, averne uno è solo ingombrare il tuo codice.

Non ci sono implicazioni significative sulle prestazioni, per quanto ne so. Ad un certo punto in futuro potrebbe essere più semplice adattare il codice utilizzando foreach per l'esecuzione su più core, ma non è qualcosa di cui preoccuparsi al momento.


I did test it a while ago, with the result that a for loop is much faster than a foreach loop. The cause is simple, the foreach loop first needs to instantiate an IEnumerator for the collection.


It seems a bit strange to totally forbid the use of something like a for loop.

There's an interesting article here that covers a lot of the performance differences between the two loops.

I would say personally I find foreach a bit more readable over for loops but you should use the best for the job at hand and not have to write extra long code to include a foreach loop if a for loop is more appropriate.


Keep in mind that the for-loop and foreach-loop are not always equivalent. List enumerators will throw an exception if the list changes, but you won't always get that warning with a normal for loop. You might even get a different exception if the list changes at just the wrong time.





for-loop