Pergunta

Disseram-me que há uma diferença de desempenho entre os seguintes blocos de código.

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

e

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

onde

List<Entity> entityList;

Não espero CLR, mas pelo que posso dizer, eles devem se resumir basicamente ao mesmo código.Alguém tem evidências concretas (caramba, eu aceitaria sujeira compactada) de uma forma ou de outra?

Foi útil?

Solução

foreach cria uma instância de um enumerador (retornado de GetEnumerator) e esse enumerador também mantém o estado durante todo o loop foreach.Em seguida, ele chama repetidamente o objeto Next() no enumerador e executa seu código para cada objeto retornado.

Na verdade, eles não se resumem ao mesmo código, o que você veria se escrevesse seu próprio enumerador.

Outras dicas

Aqui é um bom artigo que mostra as diferenças de IL entre os dois loops.

Foreach é tecnicamente mais lento, porém muito mais fácil de usar e ler.A menos que o desempenho seja crítico, prefiro o loop foreach ao loop for.

A amostra foreach corresponde aproximadamente a este código:

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

Existem dois custos aqui que um loop for regular não precisa pagar:

  1. O custo de alocação do objeto enumerador por entidadeList.GetEnumerator().
  2. O custo de duas chamadas de métodos virtuais (MoveNext e Current) para cada elemento da lista.

Um ponto perdido aqui:Uma Lista possui uma propriedade Count, que monitora internamente quantos elementos estão nela.

Um IEnumerable NÃO.

Se você programar para a interface IEnumerable e usar o método de extensão de contagem, ele enumerará apenas para contar os elementos.

Um ponto discutível, já que no IEnumerable você não pode se referir a itens por índice.

Portanto, se você quiser se concentrar em Listas e Matrizes, poderá obter pequenos aumentos de desempenho.

Se você deseja flexibilidade, use foreach e programe para IEnumerable.(permitindo o uso de linq e/ou retorno de rendimento).

Em termos de alocações, seria melhor olhar para esta postagem do blog.Mostra exatamente em que circunstâncias um enumerador é alocado no heap.

Eu acho que uma situação possível em que você poder obter um ganho de desempenho é se o tamanho do tipo enumerável e a condição do loop forem constantes;por exemplo:

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

//...

for (int i = 0; i 

Nesse caso, dependendo da complexidade do corpo do loop, o compilador poderá substituir o loop por chamadas embutidas.Não tenho ideia se o compilador .NET faz isso e é de utilidade limitada se o tamanho do tipo enumerável for dinâmico.

Uma situação em que foreach pode ter um desempenho melhor com estruturas de dados como uma lista vinculada, onde acesso aleatório significa percorrer a lista;o enumerador usado por foreach provavelmente irá iterar um item por vez, tornando cada acesso O(1) e o loop completo O(n), mas chamar o indexador significa começar no início e encontrar o item no índice correto;SOBRE) cada loop para 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.A única vez que percebi que isso era uma grande preocupação foi com estruturas como listas vinculadas.

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top