Domanda

Mi è stato detto che esiste una differenza di prestazioni tra i seguenti blocchi di codice.

foreach (Entity e in entityList)
{
 ....
}

E

for (int i=0; i<entityList.Count; i++)
{
   Entity e = (Entity)entityList[i];
   ...
}

Dove

List<Entity> entityList;

Non mi aspetto CLR, ma da quello che posso dire dovrebbero ridursi sostanzialmente allo stesso codice.Qualcuno ha prove concrete (diamine, prenderei spazzatura) in un modo o nell'altro?

È stato utile?

Soluzione

foreach crea un'istanza di un enumeratore (restituito da GetEnumerator) e tale enumeratore mantiene anche lo stato durante il corso del ciclo foreach.Quindi richiama ripetutamente l'oggetto Next() sull'enumeratore ed esegue il codice per ogni oggetto restituito.

In realtà non si riducono in alcun modo allo stesso codice, cosa che vedresti se scrivessi il tuo enumeratore.

Altri suggerimenti

Qui è un buon articolo che mostra le differenze IL tra i due loop.

Foreach è tecnicamente più lento ma molto più facile da usare e da leggere.A meno che le prestazioni non siano critiche, preferisco il ciclo foreach rispetto al ciclo for.

Il campione foreach corrisponde approssimativamente a questo codice:

using(IEnumerator<Entity> e = entityList.GetEnumerator()) {
    while(e.MoveNext()) {
        Entity entity = e.Current;
        ...
    }
}

Ci sono due costi qui che un normale ciclo for non deve pagare:

  1. Il costo dell'allocazione dell'oggetto enumeratore da parte di entitàList.GetEnumerator().
  2. Il costo di due chiamate di metodi virtuali (MoveNext e Current) per ogni elemento dell'elenco.

Un punto mancato qui:Una lista ha una proprietà Count, tiene traccia internamente di quanti elementi sono presenti in essa.

Un IEnumerable NON LO FA.

Se si programma sull'interfaccia IEnumerable e si utilizza il metodo di estensione count, verrà enumerato solo per contare gli elementi.

Un punto controverso però poiché in IEnumerable non è possibile fare riferimento agli elementi tramite indice.

Quindi, se vuoi vincolarti a elenchi e array puoi ottenere piccoli aumenti di prestazioni.

Se vuoi flessibilità usa foreach e programma su IEnumerable.(consentendo l'uso di linq e/o yield return).

In termini di allocazioni, sarebbe meglio guardare questo post sul blog.Mostra esattamente in quali circostanze un enumeratore viene allocato nell'heap.

Penso che una possibile situazione in cui tu Potrebbe ottenere un miglioramento delle prestazioni è se la dimensione del tipo enumerabile e la condizione del ciclo sono costanti;Per esempio:

const int ArraySize = 10;
int[] values = new int[ArraySize];

//...

for (int i = 0; i 

In questo caso, a seconda della complessità del corpo del ciclo, il compilatore potrebbe essere in grado di sostituire il ciclo con chiamate inline.Non ho idea se il compilatore .NET lo faccia ed è di utilità limitata se la dimensione del tipo enumerabile è dinamica.

Una situazione in cui foreach potrebbe funzionare meglio con strutture di dati come un elenco collegato in cui l'accesso casuale significa attraversare l'elenco;l'enumeratore utilizzato da foreach probabilmente itererà un elemento alla volta, rendendo ogni accesso O(1) e il ciclo completo O(n), ma chiamare l'indicizzatore significa iniziare dall'inizio e trovare l'elemento nell'indice destro;O(N) ogni ciclo per O(n^2).

Personally I don't usually worry about it and use foreach any time I need all items and don't care about the index of the item. If I'm not working with all of the items or I really need to know the index, I use for.L'unica volta in cui ho potuto vedere che è una grande preoccupazione è con strutture come gli elenchi collegati.

For Loop
for loop is used to perform the opreration n times
for(int i=0;i<n;i++)
{
l=i;
}
foreach loop

int[] i={1,2,3,4,5,6}
foreach loop is used to perform each operation value/object in IEnumarable 
foreach(var k in i)
{
l=k;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top