Em C # / VB.NET / .NET, qual loop é executado mais rapidamente for
ou foreach
?
Desde que li que um for
loop funciona mais rápido do que um foreach
loop há muito tempo, presumi que fosse verdade para todas as coleções, coleções genéricas, todas as matrizes etc.
Vasculhei o Google e encontrei alguns artigos, mas a maioria deles é inconclusiva (leia os comentários nos artigos) e é aberta.
O ideal seria ter cada cenário listado e a melhor solução para o mesmo.
Por exemplo (apenas um exemplo de como deve ser):
- para iterar uma matriz de mais de 1000 strings -
for
é melhor queforeach
- para iterar sobre
IList
cadeias (não genéricas) -foreach
é melhor quefor
Algumas referências encontradas na web para o mesmo:
- Artigo grandioso original de Emmanuel Schanzer
- CodeProject FOREACH vs. PARA
- Blog - Para
foreach
ou nãoforeach
, eis a questão - Fórum ASP.NET - NET 1.1 C #
for
vsforeach
[Editar]
Além do aspecto de legibilidade, estou realmente interessado em fatos e números. Existem aplicativos em que a última milha de otimização de desempenho compactada é importante.
c#
.net
performance
for-loop
Binoj Antony
fonte
fonte
foreach
vez defor
em C #. Se você vê aqui respostas que não fazem nenhum sentido, é por isso. Culpe o moderador, não as respostas infelizes.Respostas:
Patrick Smacchia escreveu um blog sobre este mês passado, com as seguintes conclusões:
fonte
foreach
do que para percorrer uma matriz comfor
, e você está chamando isso de insignificante? Esse tipo de diferença de desempenho pode importar para o seu aplicativo, e pode não, mas eu não descartaria isso imediatamente.foreach
s.Primeiro, uma reconvenção à resposta de Dmitry (agora excluída) . Para matrizes, o compilador C # emite praticamente o mesmo código
foreach
que seria para umfor
loop equivalente . Isso explica por que, para esse benchmark, os resultados são basicamente os mesmos:Resultados:
Em seguida, confirme se o argumento de Greg sobre o tipo de coleção é importante - altere a matriz para a
List<double>
no exemplo acima e você obtém resultados radicalmente diferentes. Não é apenas significativamente mais lento em geral, mas o foreach se torna significativamente mais lento do que o acesso por índice. Dito isto, eu quase sempre preferiria foreach a um loop for, onde ele torna o código mais simples - porque a legibilidade é quase sempre importante, enquanto a micro-otimização raramente é.fonte
List<T>
? A legibilidade também supera a micro-otimização nesse caso?List<T>
arrays. As exceções sãochar[]
ebyte[]
são tratadas com mais frequência como "pedaços" de dados, em vez de coleções normais.foreach
loops demonstram intenção mais específica do quefor
loops .O uso de um
foreach
loop demonstra para qualquer pessoa que use seu código que você está planejando fazer algo para cada membro de uma coleção, independentemente do seu lugar na coleção. Também mostra que você não está modificando a coleção original (e lança uma exceção, se tentar).A outra vantagem
foreach
disso é que ele funciona em qualquer umIEnumerable
, ondefor
apenas faz sentidoIList
, onde cada elemento realmente possui um índice.No entanto, se você precisar usar o índice de um elemento, é claro que poderá usar um
for
loop. Mas se você não precisar usar um índice, ter um está apenas sobrecarregando seu código.Não há implicações significativas de desempenho, até onde eu saiba. Em algum momento no futuro, pode ser mais fácil adaptar o código
foreach
para rodar em vários núcleos, mas isso não é algo para se preocupar no momento.fonte
foreach
.foreach
não está relacionado à programação funcional. É totalmente um paradigma imperativo de programação. Você está atribuindo mal coisas acontecendo no TPL e no PLINQforeach
.foreach
como o equivalente a umwhile
loop). Eu acho que sei que @ctford está se referindo. A biblioteca paralela de tarefas permite que a coleção subjacente forneça elementos em uma ordem arbitrária (chamando.AsParallel
um enumerável).foreach
não faz nada aqui e o corpo do loop é executado em um único thread . A única coisa que é paralelizada é a geração da sequência.foreach
e ofor
desempenho das listas normais é de frações de segundo para iterar milhões de itens. Portanto, seu problema certamente não estava diretamente relacionado ao desempenho de cada um, pelo menos não para algumas centenas de objetos. Soa como uma implementação de enumerador quebrada em qualquer lista que você estava usando.Sempre que houver argumentos sobre desempenho, basta escrever um pequeno teste para poder usar resultados quantitativos para apoiar seu caso.
Use a classe StopWatch e repita algo alguns milhões de vezes, para maior precisão. (Isso pode ser difícil sem um loop for):
Os dedos cruzaram os resultados disso e mostram que a diferença é insignificante, e você também pode fazer o que resultar no código mais sustentável
fonte
Sempre estará perto. Para uma matriz, às vezes
for
é um pouco mais rápido, masforeach
é mais expressivo, oferece LINQ etc. etc. Em geral, atenha-se aforeach
.Além disso,
foreach
pode ser otimizado em alguns cenários. Por exemplo, uma lista vinculada pode ser terrível pelo indexador, mas pode ser rápidaforeach
. Na verdade, o padrãoLinkedList<T>
nem sequer oferece um indexador por esse motivo.fonte
LinkedList<T>
está dizendo que é mais magro do queList<T>
? E se eu sempre vou usarforeach
(em vez defor
), é melhor usarLinkedList<T>
?List<T>
). É mais que mais barato inserir / remover .Meu palpite é que provavelmente não será significativo em 99% dos casos, então por que você escolheria o mais rápido em vez do mais apropriado (como é o mais fácil de entender / manter)?
fonte
É improvável que haja uma enorme diferença de desempenho entre os dois. Como sempre, quando confrontado com um "que é mais rápido?" pergunta, você deve sempre pensar "eu posso medir isso".
Escreva dois loops que fazem a mesma coisa no corpo do loop, execute e cronometre os dois e veja qual é a diferença de velocidade. Faça isso com um corpo quase vazio e um corpo em loop semelhante ao que você realmente estará fazendo. Tente também com o tipo de coleção que você está usando, porque diferentes tipos de coleções podem ter características de desempenho diferentes.
fonte
Existem boas razões para preferir
foreach
loops afor
loops. Se você pode usar umforeach
loop, seu chefe está certo que deveria.No entanto, nem toda iteração está simplesmente passando por uma lista em ordem uma por uma. Se ele está proibindo , sim, isso está errado.
Se eu fosse você, o que faria seria transformar todos os seus loops naturais em recursão . Isso o ensinaria, e também é um bom exercício mental para você.
fonte
for
loops eforeach
loops em termos de desempenho?Jeffrey Richter no TechEd 2005:
Webcast sob demanda: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US
fonte
Isto é ridículo. Não há motivo convincente para proibir o loop for, em termos de desempenho ou outro.
Consulte o blog de Jon Skeet para obter uma referência de desempenho e outros argumentos.
fonte
Nos casos em que você trabalha com uma coleção de objetos,
foreach
é melhor, mas se você incrementar um número, umfor
loop é melhor.Observe que, no último caso, você pode fazer algo como:
Mas certamente não tem um desempenho melhor, na verdade, tem desempenho pior comparado a um
for
.fonte
Isso deve te salvar:
Usar:
Para uma vitória maior, você pode levar três delegados como parâmetros.
fonte
for
loop geralmente é escrito para excluir o final do intervalo (por exemplo0 <= i < 10
).Parallel.For
também faz isso para mantê-lo facilmente intercambiável com umfor
loop comum .você pode ler sobre isso no Deep .NET - parte 1 Iteração
abrange os resultados (sem a primeira inicialização) do código-fonte .NET até a desmontagem.
por exemplo - Iteração de matriz com um loop foreach:
e - liste a iteração com o loop foreach:
e os resultados finais:
fonte
As diferenças de velocidade em um loop
for
- e umforeach
loop são pequenas quando você percorre estruturas comuns como matrizes, listas, etc.LINQ
consulta sobre a coleção é quase sempre um pouco mais lento, embora seja mais agradável para escrever! Como os outros pôsteres disseram, busque expressividade em vez de um milissegundo de desempenho extra.O que não foi dito até agora é que, quando um
foreach
loop é compilado, ele é otimizado pelo compilador com base na coleção em que ele está interagindo. Isso significa que, quando você não tiver certeza de qual loop usar, deverá usar oforeach
-lo - ele gerará o melhor loop para você quando for compilado. É mais legível também.Outra vantagem importante do
foreach
loop é que, se a implementação da sua coleção mudar (de um intarray
para umList<int>
por exemplo), seuforeach
loop não exigirá nenhuma alteração no código:O acima é o mesmo, independentemente do tipo de sua coleção, enquanto no seu
for
loop, o seguinte não será gerado se você alterarmyCollection
de umarray
para umList
:fonte
"Existe algum argumento que eu possa usar para me ajudar a convencê-lo de que o loop for é aceitável?"
Não, se o seu chefe está gerenciando ao nível de lhe dizer qual linguagem de programação constrói para usar, não há realmente nada que você possa dizer. Desculpa.
fonte
Provavelmente depende do tipo de coleção que você está enumerando e da implementação de seu indexador. Em geral, porém, o uso
foreach
provavelmente será uma abordagem melhor.Além disso, funcionará com qualquer um
IEnumerable
- e não apenas com indexadores.fonte
Isso tem as mesmas duas respostas que a maioria das perguntas "o que é mais rápido":
1) Se você não mede, você não sabe.
2) (Porque ...) Depende.
Depende de quanto o método "MoveNext ()" é caro, em relação à forma como o método "this [int index]" é caro, para o tipo (ou tipos) de IEnumerable que você estará repetindo.
A palavra-chave "foreach" é uma abreviação de uma série de operações - chama GetEnumerator () uma vez no IEnumerable, chama MoveNext () uma vez por iteração, faz alguma verificação de tipo e assim por diante. A coisa com maior probabilidade de afetar as medições de desempenho é o custo de MoveNext (), uma vez que isso é invocado O (N) vezes. Talvez seja barato, mas talvez não seja.
A palavra-chave "for" parece mais previsível, mas na maioria dos loops "for" você encontrará algo como "coleção [índice]". Parece uma operação simples de indexação de matriz, mas na verdade é uma chamada de método, cujo custo depende inteiramente da natureza da coleção que você está repetindo. Provavelmente é barato, mas talvez não seja.
Se a estrutura subjacente da coleção for essencialmente uma lista vinculada, o MoveNext é muito barato, mas o indexador pode ter um custo O (N), criando o custo real de um loop O (N * N) "for".
fonte
Cada construção de idioma tem um horário e local apropriados para uso. Há uma razão pela qual a linguagem C # possui quatro instruções de iteração separadas - cada uma existe para uma finalidade específica e tem um uso apropriado.
Eu recomendo sentar com seu chefe e tentar explicar racionalmente por que um
for
loop tem um propósito. Há momentos em que umfor
bloco de iteração descreve mais claramente um algoritmo do que umaforeach
iteração. Quando isso é verdade, é apropriado usá-los.Eu também apontaria para o seu chefe - o desempenho não é e não deve ser um problema de maneira prática - é mais uma questão de expressar o algoritmo de maneira sucinta, significativa e sustentável. Micro-otimizações como essa perdem completamente o ponto de otimização de desempenho, pois qualquer benefício real de desempenho virá do redesenho e refatoração algorítmica, e não da reestruturação em loop.
Se, após uma discussão racional, ainda houver essa visão autoritária, cabe a você decidir como proceder. Pessoalmente, eu não ficaria feliz em trabalhar em um ambiente em que o pensamento racional é desencorajado e consideraria mudar para outra posição sob outro empregador. No entanto, eu recomendo fortemente a discussão antes de ficar chateado - pode haver apenas um simples mal-entendido.
fonte
É o que você faz dentro do loop que afeta o desempenho, não a construção real do loop (supondo que seu caso não seja trivial).
fonte
Se
for
é mais rápido do queforeach
realmente está além do ponto. Eu duvido seriamente que escolher um sobre o outro tenha um impacto significativo no seu desempenho.A melhor maneira de otimizar seu aplicativo é através da criação de perfil do código real. Isso identificará os métodos que representam mais trabalho / tempo. Otimize aqueles primeiro. Se o desempenho ainda não for aceitável, repita o procedimento.
Como regra geral, eu recomendaria ficar longe das micro otimizações, pois elas raramente geram ganhos significativos. A única exceção é ao otimizar os caminhos ativos identificados (ou seja, se sua criação de perfil identificar alguns métodos altamente usados, pode fazer sentido otimizá-los extensivamente).
fonte
for
é marginalmente mais rápido queforeach
. Eu seriamente contra essa afirmação. Isso depende totalmente da coleção subjacente. Se uma classe de lista vinculada fornecer um indexador com um parâmetro inteiro, eu esperaria que o uso de umfor
loop nele fosse O (n ^ 2) enquanto oforeach
esperado fosse O (n).for
e uma pesquisa do indexador ao usoforeach
por si só. Acho que a resposta de @Brian Rasmussen está correta que, além de qualquer uso em uma coleção,for
sempre será um pouco mais rápida queforeach
. No entanto,for
além de uma pesquisa de coleção sempre será mais lenta do queforeach
por si só.for
instrução. Ofor
loop simples com uma variável de controle inteiro não é comparávelforeach
, então está pronto. Entendo o que @Brian significa e está correto como você diz, mas a resposta pode ser enganosa. Re: seu último ponto: não, na verdade,for
maisList<T>
ainda é mais rápido queforeach
.Os dois serão executados quase exatamente da mesma maneira. Escreva algum código para usar os dois e mostre a ele a IL. Ele deve mostrar cálculos comparáveis, o que significa que não há diferença no desempenho.
fonte
O for tem uma lógica mais simples de implementar, por isso é mais rápido que o foreach.
fonte
A menos que você esteja em um processo específico de otimização de velocidade, eu diria que use qualquer método que produza o código mais fácil de ler e manter.
Se um iterador já estiver configurado, como em uma das classes de coleção, o foreach é uma boa opção fácil. E se você estiver repetindo um intervalo inteiro, provavelmente será mais limpo.
fonte
Jeffrey Richter falou sobre a diferença de desempenho entre for e foreach em um podcast recente: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317
fonte
Na maioria dos casos, não há realmente nenhuma diferença.
Normalmente, você sempre precisa usar foreach quando não possui um índice numérico explícito e sempre precisa usar quando não possui uma coleção iterável (por exemplo, iterando sobre uma grade de matriz bidimensional em um triângulo superior) . Existem alguns casos em que você tem uma escolha.
Alguém poderia argumentar que para loops pode ser um pouco mais difícil de manter se números mágicos começarem a aparecer no código. Você deve estar aborrecido por não poder usar um loop for e ter que criar uma coleção ou usar um lambda para criar uma subcoleção, apenas porque os loops foram banidos.
fonte
Parece um pouco estranho proibir totalmente o uso de algo como um loop for.
Há um artigo interessante aqui que aborda muitas diferenças de desempenho entre os dois loops.
Eu diria que pessoalmente acho o foreach um pouco mais legível para loops, mas você deve usar o melhor para o trabalho em questão e não precisa escrever um código extra longo para incluir um loop foreach se um loop for for mais apropriado.
fonte
Eu encontrei o
foreach
loop que iterava através de umList
mais rápido . Veja meus resultados de teste abaixo. No código abaixo eu iterar umarray
de tamanho 100, 10000 e 100000 usando separadamentefor
eforeach
circuito para medir o tempo.ATUALIZADA
Após a sugestão @jgauffin, usei o código @johnskeet e descobri que o
for
loop comarray
é mais rápido que o seguinte,Veja meus resultados e código de teste abaixo,
fonte
Você pode realmente estragar a cabeça dele e optar por um fechamento .foreach IQueryable:
fonte
myList.ForEach(Console.WriteLine)
.Eu não esperaria que alguém encontrasse uma "enorme" diferença de desempenho entre os dois.
Eu acho que a resposta depende se a coleção que você está tentando acessar possui uma implementação mais rápida de acesso ao indexador ou uma implementação mais rápida de acesso ao IEnumerator. Como o IEnumerator geralmente usa o indexador e apenas mantém uma cópia da posição atual do índice, eu esperaria que o acesso ao enumerador fosse pelo menos tão lento ou mais lento que o acesso direto ao índice, mas não muito.
Obviamente, essa resposta não leva em conta nenhuma otimização que o compilador possa implementar.
fonte
Lembre-se de que o loop for e foreach nem sempre são equivalentes. Os enumeradores de lista lançarão uma exceção se a lista for alterada, mas você nem sempre receberá esse aviso com um loop for normal. Você pode até receber uma exceção diferente se a lista mudar no momento errado.
fonte