sexta-feira, 22 de janeiro de 2010

Dicas para melhorar a performance do .Net Compact Framework

Neste artigo veremos algumas dicas para resolver problemas comuns de desempenho em aplicações para Windows Mobile com o .Net compact framework. Devido às limitações de hardware, quando desenvolvemos para dispositivos móveis, precisamos nos preocupar com a performance da aplicação  e evitar as "bad pratices".  A maioria das orientações foram oferecidas diretamente pelo time de desenvolvimento do NET Compact Framework,  porém, devem ser usadas apenas quando for necessário para evitar códigos confusos, pouco reaproveitáveis e de difícil manutenção.

String imutável - Essa é aquela velha história que todo programador Java e/ou .Net já deve saber. Strings são imutáveis, ou seja, não é possível fazer qualquer modificação em uma String. Quando você utilizar a concatenação um novo objeto String é criado. Isso tem um alto custo e deve ser evitado SEMPRE. Ao invés de usar concatenação opte por utilizar StringBuilder.

Código a ser evitado:

String str = "string inicial";
for (int i = 0; i < 1000; i++) {
    str += "String concatenada";

}

Código a ser usado:

StringBuilder str = new StringBuilder();
for (int i = 0; i < 1000; i ++) {
    str.Append("String concatenada");

}

Uso de XML - Quando um XML for maior que 64 Kb utilize System.Xml.XmlReader, ao invés de System.Xml.XmlDocument. Para melhorar o desempenho defina a propriedade 'IgnoreWhiteSpace' como true para ignorar os espaços em branco não significativos (usados apenas para facilitar a leitura humana). Sempre que puder utilize nomes curtos  para elementos e atributos, pois, isso reduz o tamanho final do arquivo.

Reflection - Não adianta, reflections são lentos em qualquer lugar, inclusive no Desktop. Em dispositivos móveis são de 10 a 100 vezes mais lentos, portanto evite sempre. Substitua os Reflection por métodos Factory (Design patern) e uso de interfaces. Não esqueça que Web Services utilizam Reflection. Uma boa dica é utilizar o padrão singleton e manter apenas uma instância do Web Service para a aplicação inteira.

Exemplo para utilizar Web Service e evitar desperdícios de recursos com reflection.

//classe que irá gerenciar o web service
public static class WebService() {

//instância do web service  
private static WSCorreios www = null;

//método estático usado para pegar a instância do Web Service.
public static getWSCorreios() {
   if (www == null)
      www = new WSCorreios();
   return www;

}
}

//classe que irá usar o WebService
public class usarWS() {

//construtor
public usarWS() {
}
   //pega a instância do Web Service
   WSCorreios www = WebService.getWSCorreios();
 
   //usa métodos do Web Service
   www.getCep();
}
}


Boxing e Unboxing - Tipos primitivos são armazenados na pilha (STACK) e por isso não envolvem o Garbage Collector. Isso é muito bom para o desenvolvedor porque economiza muitos recursos, porém, quando é feito o boxing é guardado um tipo por referência no HEAP, e por isso a limpeza será controlada pelo Garbage Collector. Procure evitar usar boxing.

Object - Quando a aplicação acessa uma variável declarada como Object o CLR é obrigado à realizar a checagem de tipo e procurar esse objeto em tempo de execução, portanto, usar o tipo Object sempre gera um custo maior e muitas vezes desnecessário.

Collection - Sempre utilize arrays simples para tipos primitivos e System.Collection.Generic  (List) para coleções de objetos. Evite o uso de ArrayList para guardar qualquer coisa, pois além de fazer o boxing (desnecessários para tipos primitivos) ainda usa Object para guardar os objetos.

Melhor maneira para guardar coleçoes de tipos primitivos:

int[] Lista = new int[100000];
for(int i = 0; i < 100000; i++) {
      Lista[i] = i;

}

Melhor maneira para guardar coleções de objetos:

List Lista = new List(100000);
for(int i = 0; i < 100000; i++) {
        Lista.Add(i);

}

Pior maneira para guardar qualquer coisa:

ArrayList Lista = new ArrayList(100000);
for(int i = 0; i < 100000; i++) {
      Lista.Add(i);

}

####################
Referência:
http://msdn.microsoft.com/en-us/library/1766918e.aspx
http://msdn.microsoft.com/en-us/library/ms172524.aspx

Giorge Henrique Abdala

2 comentários:

  1. Perfeito.

    Estava procurando exatamente isso. Estou com problemas de performance para pegar dados de um web service e preencher um banco de dados. Suas dicas me ajudaram muito, porém, agora estou com problemas para fazer os insert e update. Tem alguma dica especial para isso??

    ResponderExcluir
  2. Olá Matheus,

    Operações com Insert/Update normalmente são lentas mesmo. Se o volume de dados for grande você pode pensar em retirar os índices das tabelas antes dos Insert´s e recria-los depois. Assim a engine do BD não precisa atualizar todos os índices.

    Uma coisa primordial é usar SqlCeResultSet para fazer os Insert/Update, visto que são muito mais rápidos que SQLPrepared. Nunca utilize String SQL com concatenação, pois é lento de mais.

    Espero ter ajudado.

    ResponderExcluir