RSS

ForEach vs List(T).ForEach

04 set

Desenvolvendo um novo trabalho, na sexta-feira decidi tentar utilizar o List<T>.ForEach, mas para ter certeza dos efeitos e de quais seriam os benefícios realizei um estudo sobre as diferenças entre o clássico ForEach e o For-Loop, e vocês poderão ver que alguns resultados realmente espantam.

Em primeiro lugar, para utilizar o List<T>.ForEach e vários dos métodos “genéricos” do .NET, ou você deve fazê-lo através de um Delegate ou utilizando expressões Lambda: no código-fonte deste artigo eu utilizei expressões Lambda.

Agora, vamos descobrir como o List<T>.ForEach passa por toda a lista de ítens contida na instância genérica de List<T>, para isso um simples teste deve bastar, vamos tentar alterar a lista.

Sabemos que o comando For é um simples If com contador, a cada Loop ele altera o contador e verifica se ele ainda atende à condição pré-determinada. Já o ForEach é um pouco mais complexo, pois ele depende de uma instância com IEnumerable ou IEnumerable(T), interface que, resumidamente, será responsável pelo gerenciamento do loop: qual o ítem atual, se existe próximo e qual será o próximo.

Conhecemos também a limitação do IEnumerable, de que a quantidade de itens na coleção não pode ser alterada durante um ForEach, e caso seja uma exceção será liberada. Portanto, vamos testar o List<T>.ForEach e tentar alterar a coleção original, e dependendo do resultado saberemos se internamente ele está executando um For ou um ForEach.

Neste exemplo vou criar uma lista de números inteiros de 0 a 20 e tentar remover os pares, assim:

List<int> pares = new List<int>();

for (int i = 0; i < 21; i++)

    pares.Add(i);

 

List<int> teste = new List<int>(pares);

teste.ForEach((int numero) => { if (Math.IEEERemainder(numero, 2) == 0) teste.Remove(numero); });

E o resultado foi uma lista contendo apenas números ímpares: 1, 3, 5, 7, 9, 11, 13, 15, 17 e 19. Ótimo, agora sabemos que internamente o List<T>.ForEach executa uma instrução do tipo For, pois mesmo alterando seu conteúdo o procedimento foi executado corretamente!

Bem, por enquanto não existe benefício nenhum em utilizar o List<T>.ForEach, pois ele pode ser 100% substituído por um outro tipo de iteração (For-Loop, por exemplo) e sua sintaxe não é das melhores. Apesar das expressões Lambda serem muito convenientes em algumas circustâncias, elas não são amigáveis, e muitas vezes podem ser difíceis de serem compreendidas. Delegate pior ainda… então, se mais de uma pessoa for realizar manutenção no código, prefira os clássicos ForEach e For, bem amigáveis e conhecidos!

Mas para esse comando estar lá, em alguma coisa a Microsoft pensou, então agora vamos testar a performance dele! Vou criar uma lista numérica para interagir com seus ítens, variando de 1000 a 95000, e utilizar cada um dos Loops que conhecemos (For com contador, For com fim determinado, ForEach e List<T>.ForEach) para ver qual apresenta o melhor resultado. Esse modelo está no código-fonte deste artigo, dentro de um BackgroundWorker para melhorar a performance do formulário.

Fiquei muito feliz quando executei o teste e vi os resultados, claramente o List<T>.ForEach apresentava o melhor resultado, no meu PC aproximadamente 16% mais baixo que o segundo!

Claro, estava testando, por isso estava em Debug. Quando fui executar o mesmo código em Release (pasta Bin\Release), veio a decepção: o List<T>.ForEach levou 85% mais tempo que o For sem contador, foi o terceiro pior tempo!! Dê uma olhada nos resultados:

Claramente o compilador otimizou muito melhor o For e o ForEach do que o List<T>.ForEach.

Então, por que diabos este método existe?! Se é mais difícil de entender, mais difícil de utilizar e mais lento, por que alguém o utilizaria!?

Talvez ele seja obrigatório para o sistema, ou até mesmo para atender o design de Orientação a Objeto do Framework, mas até que eu encontre um motivo descente para utilizá-lo, já decidi: irei continuar com o bom e velho For.

Como de costume, coloquei os testes executados aqui em um projeto na minha pasta pública do Google Docs, você pode acessá-lo por aqui.

Anúncios
 
Deixe um comentário

Publicado por em 04/09/2011 em Dev

 

Tags: , , , ,

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

 
%d blogueiros gostam disto: