Performance de iterações :: while, for, foreach, linq

Quem será o mais rápido? Para descobrir isso criei um projeto de teste da seguinte forma:

Uma classe com o método main() que instancia a classe de teste e imprime os resultados:

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         TestePerf teste = new TestePerf(); 
   6:  
   7:         Produto f = teste.listaProdutos[teste.listaProdutos.Count / 2]; 
   8:  
   9:         List<Resultado> resultados = new List<Resultado>(); 
  10:  
  11:         resultados.Add(teste.AcharLinq(f.idProduto));
  12:         resultados.Add(teste.AcharForeach(f.idProduto));
  13:         resultados.Add(teste.AcharFor(f.idProduto));
  14:         resultados.Add(teste.AcharWhile(f.idProduto)); 
  15:  
  16:         resultados.Sort(delegate(Resultado r1, Resultado r2)
  17:         {
  18:             if (Convert.ToInt32(r1.ticks) > Convert.ToInt32(r2.ticks))
  19:                 return 0;
  20:             else
  21:                 return 1;
  22:         }); 
  23:  
  24:         foreach (Resultado r in resultados)
  25:         {
  26:             Console.WriteLine(r.iterador +
  27:                     "\tTicks:" + r.ticks +
  28:                     "\tMilisegundos: " + r.miliseg);
  29:         } 
  30:  
  31:         Console.Read();
  32:     }
  33: } 

Uma classe que será o objeto da coleção percorrida:

   1: class Produto 
   2: { 
   3:     public Produto() 
   4:     { 
   5:         this.idProduto = Guid.NewGuid().ToString(); 
   6:     } 
   7:     
   8:     public string idProduto; 
   9: } 

Uma classe para retornar os resultados:

   1: class Resultado
   2: {
   3:     public string iterador;
   4:     public string ticks;
   5:     public string miliseg;
   6: 
   7:     public Resultado(string iterador, string ticks, string miliseg)
   8:     {
   9:         this.iterador = iterador;
  10:         this.ticks = ticks;
  11:         this.miliseg = miliseg;
  12:     }
  13: }

E uma classe que é responsável pela execução do teste:

   1: class TestePerf
   2: {
   3:     public List<Produto> listaProdutos;
   4:     private const int QUANTIDADE = 500000;
   5:  
   6:     public TestePerf()
   7:     {
   8:         listaProdutos = new List<Produto>();
   9:  
  10:         this.PreencherLista();
  11:     }
  12:  
  13:     private void PreencherLista()
  14:     {
  15:         for (int i = 0; i < QUANTIDADE; i++)
  16:             listaProdutos.Add(new Produto());
  17:     }
  18:  
  19:     public Resultado AcharLinq(string guid)
  20:     {
  21:         Stopwatch marcador = new Stopwatch();
  22:  
  23:         marcador.Start();
  24:  
  25:         Produto g = (from f in listaProdutos
  26:                      where f.idProduto == guid
  27:                      select f).FirstOrDefault();
  28:  
  29:         marcador.Stop();
  30:         return new Resultado(
  31:             "Linq", marcador.ElapsedTicks.ToString(), 
  32:             marcador.ElapsedMilliseconds.ToString());
  33:     }
  34:  
  35:     public Resultado AcharFor(string guid)
  36:     {
  37:         Stopwatch marcador = new Stopwatch();
  38:         marcador.Start();
  39:         Resultado result = null;
  40:  
  41:         for (int i = 0; i < listaProdutos.Count - 1; i++)
  42:         {
  43:             if (listaProdutos[i].idProduto == guid)
  44:             {
  45:                 marcador.Stop();
  46:                 result = new Resultado(
  47:                     "For", marcador.ElapsedTicks.ToString(), 
  48:                     marcador.ElapsedMilliseconds.ToString());
  49:                 break;
  50:             }
  51:         }
  52:  
  53:         return result;
  54:     }
  55:  
  56:     public Resultado AcharWhile(string guid)
  57:     {
  58:         Stopwatch marcador = new Stopwatch();
  59:         marcador.Start();
  60:         int cont = 0;
  61:         Resultado result = null;
  62:  
  63:         // Não façam isso em casa! 
  64:         while (true)
  65:         {
  66:             if (listaProdutos[cont++].idProduto == guid)
  67:             {
  68:                 marcador.Stop();
  69:                 result = new Resultado(
  70:                     "While", marcador.ElapsedTicks.ToString(), 
  71:                     marcador.ElapsedMilliseconds.ToString());
  72:                 break;
  73:             }
  74:         }
  75:  
  76:         return result;
  77:     }
  78:  
  79:     public Resultado AcharForeach(string guid)
  80:     {
  81:         Stopwatch marcador = new Stopwatch();
  82:         marcador.Start();
  83:         Resultado result = null;
  84:  
  85:         foreach (Produto f in listaProdutos)
  86:         {
  87:             if (f.idProduto == guid)
  88:             {
  89:                 marcador.Stop();
  90:                 result = new Resultado(
  91:                     "ForEa", marcador.ElapsedTicks.ToString(), 
  92:                     marcador.ElapsedMilliseconds.ToString());
  93:                 break;
  94:             }
  95:         }
  96:  
  97:         return result;
  98:     }
  99: }

Esta última classe possui quatro métodos públicos que recebem um Guid e o pesquisam em uma coleção de ‘produtos’. O tamanho desta coleção é determinada pela variável constante QUANTIDADE, que no teste está com o valor de quinhentos mil.

Um Stopwatch foi usado para marcar o tempo, ele é iniciado quando a iteração começa, parado quando o Guid é encontrado e uma classe de resultado é instanciada com as informações da iteração e retornada ao main().

O teste foi executado cinco vezes e foi feita uma média nos resultados. Quem será que ganhou? Senhores, façam suas apostas!

Primeiro teste:image

Segundo teste:image

Terceiro:image

Quarto:image

Último:image

E o vencedor é…: While! Tenho que assumir que é um dos iteradores que menos escrevo, normalmente utilizo o foreach e o linq para situações que ficariam muito complexas e/ou ‘feias’ em outros iteradores.

A idéia do post é apenas demonstrar a diferença entre cada um e não pregar qual deve ser utilizado, pois depende muito de cada situaçao e preferência do desenvolvedor. Só fica a dica para optarmos para o mais performático quando não houver diferença na utilização entre eles.

Gustavo Vedotti

Visual Studio 2008 Color Themes

Para quem gosta de ser ‘diferente’… Neste blog existem sete temas para baixar, são arquivos em extensões *.vssettings. Para utilizá-los basta abrir o VS2008 ir em Tools > Import and Export Settings Wizard, next, next, next, finish! :)

Estou usando esse no momento (Desert Nights):

image


Gustavo Vedotti

Compilation Error – BC30456

(último post do ano, uhu!). Ontem me deparei com o seguinte erro:

Server Error in ‘/’ Application.


Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: BC30456: ‘InitializeCulture’ is not a member of ‘ASP.login_alterasenha_aspx’.

Ele começou a acontecer depois que gerei uma versão de publicação do website, conforme a tela abaixo:

image

Antes o site era deixado no servidor sem estar compilado: .vb (código-fonte) e .aspx (páginas), desta forma o erro não acontecia, o site funcionava perfeitamente. Mas como sabemos isso não é muito aconselhável por questões de segurança e performance (para mais detalhes: http://msdn.microsoft.com/en-us/library/377y0s6t.aspx).

A procura do motivo do erro achei o seguinte post com algumas possíveis soluções, mas nenhuma que solucionasse meu problema. Voltando ao código e algumas horinhas quebrando a cabeça, notei que a página que estava dando erro: AlteraSenha.aspx, implementava a classe Login_AlteraSenha, conforme a diretiva abaixo:

<%@ Page Language=”VB” MasterPageFile=”~/MaterPages/Default2.master” AutoEventWireup=”false”
    CodeFile=”AlteraSenha.aspx.vb” Inherits=”Login_AlteraSenha” %>

Ao pesquisar por essa classe, descobri que outra página também a implementava:

<%@ Page Language=”VB” MasterPageFile=”~/MaterPages/Default2.master” AutoEventWireup=”false”
    CodeFile=”NovaRevendaLogin.aspx.vb” Inherits=”Login_AlteraSenha” %>

O que fiz? Alterei a segunda página, fazendo-a implementar seu respectivo code-behind  e ‘voalá’… Gerei uma nova versão publicada sem erros! Por algum motivo a compilação/publicação do ASP.NEt se confunde quando duas páginas referenciam a mesma classe como code-behind (algo não muito comum de se fazer), bom né?

 

Feliz ano novo! :)


Gustavo Vedotti

Virtual Tech Days

No último mês de novembro ocorreu uma edição do Virtual Tech Days, uma espécia de convenção on-line feita pela Microsoft, nos dias 24, 25 e 26. As apresentações foram divididas nas seguintes categorias:

Dia 24

  • Designer

Dia 25

  • Web Development (For Developers)
  • Database Development SQL Server (For Developers)
  • Cloud Computing & Software + Services (For Developers)
  • Save Datacentre Cost through Integrated Physical & Virtual Management (For IT Pros)
  • Building a Powerful and Optimized Enterprise Solution on Windows Platform (For IT Pros)

Dia 26

  • Client Development (For Developers)
  • Tools (For Developers)
  • Chalk Talks, Hands-on-Labs & Showcase (For Developers)
  • SQL Server Administration (For IT Pros)
  • Unified Communication (For IT Pros)

Algumas apresentações que recomendo:

  • Architecting Rich Internet Ecommerce Applications Using Silverlight & Commerce Server
  • Building Data-Driven Applications with Silverlight 2 and the new Silverlight Control Pack
  • Internet Explorer 8 for Web Developers

O bom nisso tudo é que eles disponibilizaram as apresentações e vídeos para download, basta ter um Passport Live =) Para quem se interessar o endereço é esse: http://www.virtualtechdays.com


Gustavo Vedotti

Grupo de discussão sobre Commerce Server

Um amigo de trabalho especialista em Commerce Server, teve a iniciativa de criar um grupo de discussão sobre Commerce Server específico para o mercado brasileiro.

O grupo foi criado para troca de experiência, centralização de conhecimento, resoluções de problemas, divulgação de empresas e profissionais que trabalham com Commerce Server e divulgação de cursos e eventos.

Para maiores informações basta acessaro site: www.commerceserver.com.br.

Até


Gustavo Vedotti

Next Page »