In .NET, quale ciclo viene eseguito più velocemente, "for" o "foreach"?


345

In C # / VB.NET / .NET, quale ciclo viene eseguito più velocemente foroforeach ?

Da quando ho letto che un forloop funziona molto più velocemente di un foreachloop molto tempo fa, ho pensato che fosse vero per tutte le raccolte, raccolte generiche, tutti gli array, ecc.

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

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 un array di oltre 1000 stringhe - forè meglio diforeach
  2. per iterare su IListstringhe (non generiche) - foreachè meglio difor

Alcuni riferimenti trovati sul web per lo stesso:

  1. Grande vecchio articolo originale di Emmanuel Schanzer
  2. CodeProject FOREACH vs. PER
  3. Blog - To to foreachnot not foreach, questa è la domanda
  4. Forum ASP.NET - NET 1.1 C # forvsforeach

[Modificare]

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


3
La differenza esiste ancora. Le matrici in particolare dovrebbero essere altrettanto veloci sotto la foreach, ma per tutto il resto, i semplici loop sono più veloci. Naturalmente, la maggior parte delle volte, questo non farà alcuna differenza e, naturalmente, un compilatore JIT intelligente potrebbe teoricamente eliminare la differenza.
jalf

3
Senza contesto, non posso sapere esattamente cosa stai facendo, ma cosa succede quando ti imbatti in un array parzialmente riempito?
Chris Cudmore,

6
A proposito, 2 milioni di hit / mese non sono niente di spaventoso. In media è meno di un colpo al secondo.
Mehrdad Afshari,

37
Nota importante : questa domanda è stata unita ieri con una domanda totalmente indipendente dall'obbligo di utilizzare foreachanziché forin C #. Se vedi qui delle risposte che non hanno alcun senso, ecco perché. Dai la colpa al moderatore, non alle risposte sfortunate.
TED,

7
@TED ​​Oh, mi chiedevo da dove venissero tutti i commenti "il tuo capo è un idiota", grazie
Gaspa79,

Risposte:


350

Patrick Smacchia ha scritto un blog sull'ultimo mese, con le seguenti conclusioni:

  • per i loop su List sono un po 'più di 2 volte più economici dei loop foreach su List.
  • Il looping sull'array è circa 2 volte più economico del looping sull'elenco.
  • Di conseguenza, il looping sull'array usando for è 5 volte più economico del looping su List usando foreach (cosa che credo sia ciò che facciamo tutti).

130
Tuttavia, non dimenticare mai: "L'ottimizzazione prematura è la radice di tutti i mali".
Oorang,

18
@Hardwareguy: una volta che sai che per è quasi impercettibilmente più veloce, perché non dovresti iniziare a usarlo in generale? Non ci vuole altro tempo.
DevinB,

47
@devinb, usare "for" è più difficile che usare "foreach" in quanto aggiunge codice, un'altra variabile, una condizione che devi controllare, ecc. Quante volte hai visto un errore off-by-one in un ciclo "foreach" ?
tster,

35
@Hardwareguy, let me see if I got this straight. It takes 5 times longer to loop through a list with foreach than it does to loop through an array with for, and you're calling that insignificant? That kind of a performance difference might matter for your application, and it might not, but I wouldn't just dismiss it out of hand.
Robert Harvey

44
Leggendo il post del blog sembra che i test siano stati eseguiti in Debug e non in Release, quindi potrebbe avere un fattore. Inoltre, la differenza è specifica solo per il sovraccarico del loop. Non influisce affatto sul tempo di esecuzione del corpo del loop, che nella maggior parte dei casi è molto più lungo del tempo necessario per passare all'elemento successivo dell'elenco. È una buona informazione sapere quando hai identificato che c'è chiaramente un problema e hai misurato la differenza nella tua app in modo specifico e c'è un notevole miglioramento ma sicuramente non un consiglio generale per rimuovere tutti i messaggi di posta foreachelettronica.
Davy8,

164

Innanzitutto, una controproposta alla risposta di Dmitry (ora cancellata) . Per gli array, il compilatore C # emette in gran parte lo stesso codice foreachcome per un forloop 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 che il punto di Greg sul tipo di raccolta sia importante: cambia l'array in a List<double>in quanto sopra e otterrai risultati radicalmente diversi. Non solo è significativamente più lento in generale, ma foreach diventa significativamente più lento rispetto all'accesso per indice. Detto questo, preferirei quasi sempre foreach a un ciclo for dove semplifica il codice, perché la leggibilità è quasi sempre importante, mentre raramente la micro-ottimizzazione lo è.


"cambia l'array in una Lista <doppia> in quanto sopra e otterrai risultati radicalmente diversi" Molto interessante, non ci avevo pensato
johnc

5
Date le strane differenze nei risultati tra i miei test e i benchmark di altre persone, penso che questo meriterà un post sul blog ...
Jon Skeet,

1
Quale preferisci quasi sempre tra array e List<T>? La leggibilità supera anche la micro-ottimizzazione in quel caso?
Giovanni B

12
@JohnB: Sì, quasi sempre preferisco gli List<T>array. Le eccezioni sono char[]e byte[]che sono più spesso trattate come "blocchi" di dati piuttosto che raccolte normali.
Jon Skeet,

Incredibile, sto ottenendo una differenza ancora più aggressiva sulla mia macchina, quasi il 10% a favore di foreach su array semplici. Sto indovinando selvaggiamente che tutto ciò deriva dal jitter non doversi preoccupare della variabile extra, dei controlli associati, ecc. Sarebbe molto interessante se qualcuno avesse una spiegazione approfondita di questo.
Tamir Daniely,

162

foreachi loop dimostrano un intento più specifico rispetto ai forloop .

Usare un foreach ciclo dimostra a chiunque usi il tuo codice che stai pianificando di fare qualcosa per ogni membro di una raccolta, indipendentemente dal suo posto nella raccolta. Mostra anche che non stai modificando la raccolta originale (e genera un'eccezione se provi a farlo).

L'altro vantaggio foreachè che funziona su qualsiasi IEnumerable, dove forha senso solo perIList , dove ogni elemento ha effettivamente un indice.

Tuttavia, se è necessario utilizzare l'indice di un elemento, ovviamente dovrebbe essere consentito l'uso di un forciclo. Ma se non hai bisogno di usare un indice, averne uno sta solo ingombrando il tuo codice.

Per quanto ne so, non ci sono implicazioni significative in termini di prestazioni. Ad un certo punto in futuro potrebbe essere più facile adattare il codice usando foreachper eseguire su più core, ma non è qualcosa di cui preoccuparsi in questo momento.


23
ctford: No non lo è. Il compilatore non può certo riordinare gli elementi in foreach. foreachnon è affatto correlato alla programmazione funzionale. È totalmente un paradigma imperativo della programmazione. Stai attribuendo erroneamente cose che accadono in TPL e PLINQ foreach.
Mehrdad Afshari,

13
@BlueTrin: Certamente garantisce l'ordinamento (la sezione specifica C # 8.8.4 definisce formalmente foreachcome un equivalente di un whileciclo). Penso di sapere che @ctford si sta riferendo. La libreria parallela di attività consente alla raccolta sottostante di fornire elementi in un ordine arbitrario (chiamando .AsParallelun elenco numerabile). foreachnon fa nulla qui e il corpo del loop viene eseguito su un singolo thread . L'unica cosa che è parallelizzata è la generazione della sequenza.
Mehrdad Afshari,

6
Enumerable.Select has an overload that lets you obtain the index of the item, so even the need for an index does not mandate using for. See msdn.microsoft.com/en-us/library/bb534869.aspx
TrueWill

5
ForEach is handy for readability and saving typing. Costs matter, though; changing 2 or 3 for-loops in a document designer UI that I made, from (for each obj in list) to (for i=0 to list.count-1) reduced response time from 2-3 sec per edit to about .5 sec per edit on a small document just looping thru a few hundred objects. Now for even huge documents, there is no increase in time to loop all. I have no idea how this happened. What I do know is that the alternative was a complicated scheme to only loop a subset of the objects. I'll take the 5 minute change any day! - not micro-optimisation.
FastAl

5
@FastAl La differenza tra foreache le forprestazioni per gli elenchi normali sono le frazioni di secondo per l'iterazione su milioni di articoli, quindi il tuo problema non è stato direttamente correlato alle prestazioni di ogni singola unità, almeno non per alcune centinaia di oggetti. Sembra un'implementazione dell'enumeratore non funzionante in qualsiasi elenco si stia utilizzando.
Mike Marynowski,

53

Ogni volta che ci sono argomenti sulle prestazioni, devi solo 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 la precisione. (Questo 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 hanno incrociato i risultati di questo spettacolo che la differenza è trascurabile e potresti anche fare qualsiasi cosa dia il risultato nel codice più gestibile


13
Ma non puoi confrontare le prestazioni di for e foreach. Dovrebbero essere usati in diverse circostanze.
Michael Krelin - hacker

7
Sono d'accordo con te Michael, non dovresti scegliere quale usare in base alle prestazioni - dovresti scegliere quello che ha più senso! Ma se il tuo capo dice "Non usare per perché è più lento di foreach", questo è l'unico modo per convincerlo che la differenza è trascurabile
Rob Fonseca-Ensor,

"(Questo potrebbe essere difficile senza un ciclo for)" O puoi usare un ciclo while.
jonescb,

49

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, foreachpuò essere ottimizzato in alcuni scenari. Ad esempio, un elenco collegato potrebbe essere terribile per l'indicizzatore, ma potrebbe essere veloce per foreach. In realtà, lo standard LinkedList<T>non offre nemmeno un indicizzatore per questo motivo.


Quindi stai dicendo che LinkedList<T>è più magro di List<T>? E se userò sempre foreach(invece di for), starò meglio usando LinkedList<T>?
John B

2
@JohnB - non più snello; solo diverso. Ad esempio, ogni nodo in un elenco collegato ha riferimenti aggiuntivi che non sono necessari per una matrice piatta (che è anche alla base List<T>). È più che è più economico inserire / rimuovere .
Marc Gravell

36

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


6
@klew, se effettivamente profilassi il tuo codice non dovresti indovinare quale 20% deve essere il più veloce possibile. Probabilmente scopriresti anche che il numero effettivo di loop che devono essere veloci è molto più basso. Inoltre, stai davvero dicendo che l'atto del looping è dove passi il tuo tempo, al contrario di quello che fai effettivamente in quel loop?
tster,

32

È improbabile che ci sia un'enorme differenza di prestazioni tra i due. Come sempre, di fronte a un "che è più veloce?" domanda, dovresti sempre pensare "Posso misurarlo".

Scrivi due loop che fanno la stessa cosa nel corpo del loop, eseguili e cronometri entrambi, e vedi qual è la differenza di velocità. Fallo sia con un corpo quasi vuoto, sia con un corpo ad anello simile a quello che effettivamente farai. Provalo anche con il tipo di raccolta che stai utilizzando, perché diversi tipi di raccolte possono avere caratteristiche prestazionali diverse.


32

Vi sono ottime ragioni per preferire i foreach loop rispetto ai forloop. Se puoi usare un foreachloop, il tuo capo ha ragione che dovresti.

Tuttavia, non tutte le iterazioni stanno semplicemente attraversando un elenco in ordine uno per uno. Se glielo proibisce , sì, è sbagliato.

If I were you, what I would do is turn all of your natural for loops into recursion. That'd teach him, and it's also a good mental exercise for you.


How does recursion compare to for loops and foreach loops performance-wise?
JohnB

Dipende. Se usi la ricorsione della coda e il tuo compilatore è abbastanza intelligente da notare, può essere identico. OTOH: Se non lo fa e fai qualcosa di stupido come passare molti dati non immuni (immutabili) come parametri o dichiarare grandi strutture nello stack come locali, può essere davvero molto lento (o anche esaurire la RAM).
TED

Ahhh. Capisco perché l'hai chiesto ora. Questa risposta è andata a una domanda completamente diversa. Per qualche bizzarro motivo, Jonathan Sampson ha unito i due ieri. Non avrebbe dovuto farlo davvero. Le risposte unite non avranno alcun senso qui.
TED,

18

Jeffrey Richter su TechEd 2005:

"Nel corso degli anni ho imparato che il compilatore C # è sostanzialmente un bugiardo per me." .. "Si tratta di molte cose." .. "Come quando fai un ciclo foreach ..." .. "... questa è una piccola riga di codice che scrivi, ma quello che il compilatore C # sputa per farlo è fenomenale. Emette un prova / infine blocco lì, all'interno del blocco finally lancia la tua variabile su un'interfaccia IDisposable, e se il cast ha successo chiama il metodo Dispose su di essa, all'interno del loop chiama ripetutamente la proprietà Current e il metodo MoveNext all'interno del loop, gli oggetti vengono creati sotto le copertine. Molte persone usano foreach perché è un codice molto semplice, molto facile da fare .. ".." foreach non è molto buono in termini di prestazioni,

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


12

Questo è ridicolo. Non c'è motivo convincente per vietare il for-loop, le prestazioni o altro.

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



The loop construct that is faster depends on what you need to iterate over. Another blog that benchmarks multiple iterations over multiple kinds of objects, such as DataRows and custom objects. It also includes the performance of the While loop construct and not just the for and foreach looping constructs.
Free Coder 24

11

In cases where you work with a collection of objects, foreach is better, but if you increment a number, a for loop is better.

Note that in the last case, you could do something like:

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

But it certainly doesn't perform better, it actually has worse performance compared to a for.


"Better" is debateable: It is slower and the dnspy debugger won't break into a C# foreach (although VS2017 debugger will). Sometimes more readable but if you support languages without it, it can be annoying.
Zeek2

10

This should save you:

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

Use:

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

For greater win, you may take three delegates as parameters.


1
Una piccola differenza è che di forsolito viene scritto un loop per escludere la fine dell'intervallo (ad esempio 0 <= i < 10). Parallel.Forlo fa anche per mantenerlo facilmente intercambiabile con un forloop comune .
Groo

9

puoi leggerlo in Deep .NET - Iterazione della parte 1

copre i risultati (senza la prima inizializzazione) dal codice sorgente .NET fino allo smontaggio.

ad esempio - Iterazione di array con un ciclo foreach: inserisci qui la descrizione dell'immagine

e - elenco iterazione con ciclo foreach: inserisci qui la descrizione dell'immagine

e i risultati finali: inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


8

Le differenze di velocità in a for- e a foreach-loop sono minuscole quando si scorre in loop attraverso strutture comuni come array, elenchi, ecc. E si esegue unLINQ query sulla raccolta è quasi sempre leggermente più lento, sebbene sia più bello scrivere! Come dicevano gli altri manifesti, cerca espressività piuttosto che un millisecondo di prestazioni extra.

Ciò che non è stato detto finora è che quando un foreachciclo viene compilato, viene ottimizzato dal compilatore in base alla raccolta su cui sta ripetendo. Ciò significa che quando non sei sicuro di quale ciclo utilizzare, dovresti usare il foreachciclo: genererà il ciclo migliore per te quando viene compilato. È anche più leggibile.

Un altro vantaggio chiave del foreachciclo è che se l'implementazione della raccolta cambia (da un int arraya un List<int>ad esempio), il foreachciclo non richiederà alcuna modifica del codice:

foreach (int i in myCollection)

Quanto sopra è lo stesso, indipendentemente dal tipo di raccolta, mentre nel tuo forciclo, quanto segue non verrà generato se hai cambiato myCollectionda arraya a List:

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

7

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

No, se il tuo capo è micromanage al livello di dirti quale linguaggio di programmazione costruisce da usare, non c'è davvero niente che puoi dire. Scusate.


7

Probabilmente dipende dal tipo di raccolta che stai enumerando e dall'implementazione del suo indicizzatore. In generale, tuttavia, foreachè probabile che l' utilizzo sia un approccio migliore.

Inoltre, funzionerà con qualsiasi IEnumerable, non solo con gli indicizzatori.


7

Questo ha le stesse due risposte della maggior parte delle domande "che è più veloce":

1) Se non misuri, non lo sai.

2) (Perché ...) Dipende.

Dipende da quanto è costoso il metodo "MoveNext ()", rispetto a quanto è costoso il metodo "this [int index]", per il tipo (o tipi) di IEnumerable su cui verrà ripetuto.

La parola chiave "foreach" è una scorciatoia per una serie di operazioni: chiama GetEnumerator () una volta su IEnumerable, chiama MoveNext () una volta per iterazione, esegue un controllo del tipo e così via. La cosa che più probabilmente influenzerà le misurazioni delle prestazioni è il costo di MoveNext () poiché viene richiamato O (N) volte. Forse è economico, ma forse non lo è.

La parola chiave "for" sembra più prevedibile, ma nella maggior parte dei cicli "for" troverai qualcosa come "collection [index]". Sembra una semplice operazione di indicizzazione di array, ma in realtà è una chiamata di metodo, il cui costo dipende interamente dalla natura della raccolta su cui stai ripetendo. Probabilmente è economico, ma forse non lo è.

Se la struttura sottostante della raccolta è essenzialmente un elenco collegato, MoveNext è poco costoso, ma l'indicizzatore potrebbe avere un costo O (N), facendo il vero costo di un ciclo "for" O (N * N).


6

Ogni costrutto linguistico ha un tempo e un luogo adeguati per l'uso. C'è una ragione per cui il linguaggio C # ha quattro istruzioni di iterazione separate : ognuna è lì per uno scopo specifico e ha un uso appropriato.

Raccomando di sedermi con il tuo capo e di provare a spiegare razionalmente perché un forloop ha uno scopo. Ci sono momenti in cui un forblocco di iterazione descrive più chiaramente un algoritmo rispetto a foreachun'iterazione. Quando questo è vero, è opportuno usarli.

Vorrei anche segnalare al tuo capo - le prestazioni non sono, e non dovrebbero essere un problema in alcun modo pratico - è più una questione di espressione dell'algoritmo in modo succinto, significativo, mantenibile. Le microottimizzazioni come questa mancano completamente del punto di ottimizzazione delle prestazioni, poiché qualsiasi reale vantaggio in termini di prestazioni verrà dalla riprogettazione e dal refactoring algoritmici, non dalla ristrutturazione ad anello.

Se, dopo una discussione razionale, esiste ancora questa visione autoritaria, sta a te decidere come procedere. Personalmente, non sarei felice di lavorare in un ambiente in cui il pensiero razionale è scoraggiato e prenderei in considerazione l'idea di trasferirmi in un'altra posizione sotto un diverso datore di lavoro. Tuttavia, consiglio vivamente la discussione prima di arrabbiarti - potrebbe esserci un semplice malinteso sul posto.


5

È ciò che fai all'interno del ciclo che influenza la performance, non il vero costrutto del ciclo (supponendo che il tuo caso non sia banale).


5

Se forè più veloce di quanto non foreachsia davvero oltre il punto. Dubito seriamente che scegliere l'uno rispetto all'altro avrà un impatto significativo sulla tua performance.

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

Come regola generale, consiglierei di stare alla larga dalle micro ottimizzazioni poiché raramente produrranno guadagni significativi. L'unica eccezione è quando si ottimizzano i percorsi caldi identificati (ovvero se la profilazione identifica alcuni metodi altamente utilizzati, può avere senso ottimizzarli ampiamente).


Se l'unico tipo di ottimizzazione che dovessi fare nei progetti su cui lavoro sono state le micro ottimizzazioni, sarei un camper felice. Purtroppo, non è mai così.
Yannick Motton,

2
forè leggermente più veloce di foreach. Mi opporterei seriamente a questa affermazione. Dipende totalmente dalla collezione sottostante. Se una classe di elenco collegata fornisce a un indicizzatore un parametro intero, mi aspetto che l'uso di un forciclo su di esso sia O (n ^ 2) mentre foreachci si aspetta che sia O (n).
Mehrdad Afshari,

@Merhdad: in realtà è un buon punto. Stavo solo pensando al normale caso di indicizzazione di un elenco (cioè array). Riformulerò per riflettere questo. Grazie.
Brian Rasmussen,

@Mehrdad Afshari: l'indicizzazione di una raccolta per intero può essere molto più lenta dell'enumerazione su di essa. Ma stai effettivamente confrontando l'utilizzo for e una ricerca dell'indicizzatore con l'utilizzo foreachda solo. Penso che la risposta di @Brian Rasmussen sia corretta che, a parte qualsiasi utilizzo con una collezione, forsarà sempre leggermente più veloce di foreach. Tuttavia, foroltre a una ricerca della raccolta sarà sempre più lenta che foreachda sola.
Daniel Pryden,

@Daniel: O hai un array semplice, per il quale entrambi genereranno codice identico, o c'è un indicizzatore coinvolto quando usi l' foristruzione. Il forciclo semplice con una variabile di controllo intero non è paragonabile a foreach, quindi è fuori. Capisco cosa significa @Brian ed è corretto come dici tu, ma la risposta può essere fuorviante. Re: l'ultimo punto: no, in realtà, fornel corso List<T>è ancora più veloce di foreach.
Mehrdad Afshari,

4

I due funzioneranno quasi esattamente allo stesso modo. Scrivi un codice per usare entrambi, quindi mostragli l'IL. Dovrebbe mostrare calcoli comparabili, senza alcuna differenza nelle prestazioni.


Il compilatore riconosce i loop foreach utilizzati su array / IList ecc. E li modifica in per loop.
Callum Rogers,

3
Mostragli linee di prova incomprensibile che è OK e chiedi la sua prova che non è OK.
cjk

3

for ha una logica più semplice da implementare, quindi è più veloce di foreach.


3

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

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



3

Nella maggior parte dei casi non c'è davvero alcuna 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 es. Iterando su una griglia di array bidimensionale in un triangolo superiore) . Ci sono alcuni casi in cui hai una scelta.

Si potrebbe sostenere 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 seccato per non essere in grado di usare un ciclo for e di creare una raccolta o usare un lambda per creare un subcollection invece solo perché i loop per sono stati vietati.


3

Sembra un po 'strano vietare totalmente l'uso di qualcosa come un ciclo for.

C'è un articolo interessante qui che copre molte delle differenze di prestazioni tra i due loop.

Direi personalmente che trovo foreach un po 'più leggibile per i loop ma dovresti usare il meglio per il lavoro a portata di mano e non devi scrivere un codice extra lungo per includere un ciclo foreach se un ciclo for è più appropriato.


Citazione essenziale dall'articolo a cui ti colleghi: "... se stai pensando di scrivere un codice ad alte prestazioni che non sia per le raccolte, usa per il ciclo. Anche per le raccolte, foreach può sembrare utile quando lo usi, ma non è così efficiente."
NickFitz,

3

Ho trovato il foreachciclo che scorre List più velocemente . Vedi i miei risultati dei test di seguito. Nel codice qui sotto ho iterato una arraydimensione di 100, 10000 e 100000 separatamente usando fore foreachloop per misurare il tempo.

inserisci qui la descrizione dell'immagine

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

AGGIORNATO

Dopo il suggerimento di @jgauffin ho usato il codice @johnskeet e ho scoperto che il forciclo con arrayè più veloce del seguente,

  • Foreach loop con array.
  • Per loop con elenco.
  • Foreach loop con list.

Vedi i miei risultati dei test e il codice di seguito,

inserisci qui la descrizione dell'immagine

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

3
Questo è un test molto scarso. a) fai troppe poche iterazioni per ottenere una risposta conclusiva b) That Thread.Sleep non aspetta davvero un millisecondo. Usa lo stesso metodo di Jon Skeet nella sua risposta.
jgauffin,

1
Il 99,99% del tempo è sicuramente trascorso nel thread.sleep (il che non garantisce la velocità con cui tornerà, tranne che non lo farà prima almeno quel tempo). Il looping è molto veloce e il sonno è molto lento, non si utilizza il successivo per testare il primo.
Ronan Thibaudau,

3

Puoi davvero fregare con la testa e optare per una chiusura IQueryable .foreach:

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

3
Sostituirei la tua riga di codice con myList.ForEach(Console.WriteLine).
Mehrdad Afshari,

2

Non mi aspetto che nessuno trovi una "enorme" differenza di prestazioni tra i due.

Immagino che la risposta dipenda dal fatto che la raccolta a cui stai tentando di accedere abbia un'implementazione dell'accesso all'indicizzatore più veloce o un'implementazione dell'accesso all'Iumerumer più veloce. Poiché IEnumerator utilizza spesso l'indicizzatore e contiene solo una copia della posizione corrente dell'indice, mi aspetto che l'accesso all'enumeratore sia almeno altrettanto lento o più lento dell'accesso diretto all'indice, ma non di molto.

Naturalmente questa risposta non tiene conto delle ottimizzazioni che il compilatore può implementare.


Il compilatore C # fa pochissima ottimizzazione, lo lascia davvero al JITter.
ljs

Bene, JITter è un compilatore ... Giusto?
JohannesH,

2

Tieni presente che for-loop e foreach-loop non sono sempre equivalenti. Gli enumeratori di elenchi genereranno un'eccezione se l'elenco cambia, ma non riceverai sempre quell'avvertimento con un normale ciclo for. Potresti persino ottenere un'eccezione diversa se l'elenco cambia al momento sbagliato.


Se l'elenco sta cambiando da sotto di te, non puoi fare affidamento sul fatto che l'enumeratore esegua il backup di un ciclo foreach per dirtelo. Non verificherà più dopo che ti verrà restituito il valore, risultando in una gara.
Hoodaticus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.