VB.NET - Otimização e Performance - Parte II

Vimos na primeira parte dessa matéria como o uso do tipo de dado correto pode tornar o seu código mais eficiente. Veremos agora mais algumas dicas.

Declarações

Vimos na matéria anterior que usar Early Binding é mais performático do que usar Late binding. Mas mesmo quando usamos Early Binding, devemos ter certeza de declarar o objeto do tipo mais específico possível. Vejamos um exemplo:

Hierarquia da classe Label:

System.Object
  System.MarshalByRefObject
    System.ComponentModel.Component
      System.Windows.Forms.Control
        System.Windows.Forms.Label

Hierarquia da classe Button:

System.Object
  System.MarshalByRefObject
    System.ComponentModel.Component
      System.Windows.Forms.Control
        System.Windows.Forms.ButtonBase
          Syste m.Windows.Forms.Button

Se desejarmos criar um objeto que possa referenciar tanto um Button quanto um Label, devemos declará-lo como Control, que é a classe mais próxima de ambos. O que ocorre, é que muitas vezes quando nos deparamos com essa situação, declaramos o objeto como Object, e isso é um erro muito comum.

Propriedades, Variáveis e Constantes

Desconsiderando o conceito de encapsulamento e focando em performance, podemos dizer que é melhor utilizar variáveis ao invés de propriedades. Variáveis fazem acesso simplesmente ao local da memória onde está o dado, enquanto propriedades exigem chamadas extras dos métodos Get e Set, o que gera um processamento adicional.

Cuidado também com variáveis declaradas com "WithEvents", pois o compilador implementa-as como propriedades.

Já as constantes são bem superiores às variáveis, pois seus valores são compilados dentro do código e não exigem pesquisa nem acesso à memória, exceto as constantes do tipo Date ou Decimal.

Options Settings

Usar Option Explicit On, força você declarar todas as variáveis, o que torna o seu código mais legível e menos sujeito a erros. Procure usar sempre essa opção ativa. Procure também usar declaração de variável usando "As", caso contrário ela será do tipo Object, o que já vimos não ser um tipo ótimo.

Option Strict On desabilita as conversões implícitas e obriga todas as variáveis serem declaradas utilizando "As". Dessa forma, o Late binding é desabilitado, a não ser que você declare explicitamente o objeto como Object.

Option Compare binary define que as strings serão comparadas e ordenadas com base na sua representação binária. Isso aumenta a performance.

Acesso a disco

Temos básicamente 3 (três) maneiras de acessar arquivos com o Visual Basic .NET:

  • Usando as funções de compatibilidade do VB: OpenFile, WriteLine, etc

  • Usando o FSO (FileSystemObject)

  • Usando as classes do Namespace System.IO

As duas primeiras opções existem por questões de compatibilidade entre as versões anteriores do VB (FSO para scripts). Mas na verdade elas são implementadas em Wrapper Objects que encapsulam o acesso às classes do Namespace System.IO, sendo assim, nem precisa dizer que acessar utilizando diretamente as classes do System.IO é bem mais eficiente.

Operações

Algumas coisas são óbvias, mas às vezes não seguimos. Por exemplo, se vamos fazer operações entre variáveis onde não importa a parte decimal ou fracionária, não faz sentido declarar a variável como um tipo diferente de Integer ou Long. Da mesma forma se na operação entre os inteiros não lhe importa o resto, use o operador "\" ao invés de "/", isso é mais ou menos 10 vezes mais rápido.

Concatenções

Sempre que você for concatenar Strings, use o operador "&" e evite o uso do operador "+". O segundo, realiza checagem de tipo em tempo de execução, o que obviamente causa uma perda de performance.

Caso a quantidade de strings que serão concatenadas seja muito grande, use a classe StringBuilder, e você verá a visível diferença de velocidade. Exemplo:

Dim s As String
Dim sb As New StringBuilder

For i As Integer = 0 To 100000
   sb.Append(i.ToString & " ")
Next

For i As Integer = 0 To 100000
   S &= i.ToString & " "
Next

Execute os dois loops. Não vale babar ao notar a diferença de velocidade.

Strings Functions

É muito comum a conversão e/ou formatação de strings em nossos programas. No VB temos a função Format, que formata a string de acordo com a formatação passada como parâmetro. Mas quando trabalhamos com .NET, essa função (Que ainda existe por questões de compatibilidade) realiza muitas verificações, conversões e outros processamentos incluindo formatação de acordo com a cultura corrente, e isso é claro torna o código menos eficiente. Prefira usar o método "ToString". Ele é muito mais rápido do que a função Format em relação à formatação e muito mais eficiente do que o método CStr, por exemplo, em relação a conversão.

Em relação aos métodos Asc e Chr, ambos trabalham com caracteres single-byte e double-byte, e o valor de retorno depende do Code page da Thread atual. Já os métodos AscW e ChrW trabalham exclusivamente com caractere Unicode, e são independentes da cultura e do Code page da Thread atual, sendo assim mais eficientes. Só como observação, o tipo String no .NET é representado como uma seqüência de caracteres Unicode.

Testes Booleanos

Não existe diferença de performance entre fazer um teste de uma variável booleana usando o sinal de igual "=" ou simplesmente usando a própria variável sozinha.

Exemplo:

Dim Flag as Boolean
If Flag = True ...

É igual a:

Dim Flag as Boolean
If Flag ...

Mas a segunda forma é mais compacta e consequentemente torna o seu código menor, claro que isso é um detalhe, mas eu achei interessante mostrar.

Curto circuito

Sempre que possível use os operadores AndAlso e OrElse. Eles evitam avaliações desnecessárias, tipo:

Dim A1, A2, A3, ... as Boolean
A1 = True
A2 = False
A3 = True
...

If  A1 AndAlso A2 AndAlso A3 … then ...

No caso acima, ao verificar que A2 é falso, não faz sentido continuar a avaliar as outras variáveis, no caso a A3, pois sempre o resultado será Falso.

Procedimentos

Tamanho do procedimento

Todos os procedimentos ( functions e Subs ) estão sujeitos ao JIT (Just-in-Time) compilation, ou seja, ele não é compilado até a primeira vez que ele é acessado. O JIT tenta realizar algumas otimizações enquanto compila o procedimento, como geração de código inline no caso de procedimentos pequenos. Se o procedimento for grande, ele não gozará dessa otimização. O ideal é que ele tenha menos que 1000 linhas de código.

Chamadas e Retorno

Nas versões anteriores do VB, o local onde a chamada de um método era feita, fazia diferença na performance da aplicação, ou seja, se uma função chamasse outra no mesmo módulo, era mais rápido do que chamar uma função em outro módulo. No VB.NET, isso não faz diferença.

Use "Return" sempre que precisar retornar algo a partir da função, pois o compilador irá otimizar o código de forma melhor do que se você usar Exit Function, Exit Sub, "NomeFunção = ValorRetorno", etc.

Argumentos

Quando você passa um argumento para um método usando ByRef, o VB.NET copiará apenas o ponteiro para o local onde a variável está armazenada na memória. Tanto faz se o tipo passado é Reference Type ou Value Type. Já se passar usando ByVal (Default no VB.NET), o conteúdo da variável será copiado. No caso de Reference Types, como o seu conteúdo é apenas um ponteiro, não irá fazer diferença.

Em relação à performance de ambos, na maioria dos casos não há diferença significante entre as duas formas, especialmente entre os Reference Types.

Obs.: Caso o argumento seja um objeto muito grande, usar ByVal gerará um Overhead devido a cópia do objeto. Nesse caso, prefira usar ByRef.

Chamadas entre processos

Evite chamadas entre processos, chamadas remotas e chamadas entre Application Domains, devido ao overhead gerado pelo uso de marshaling.

Quando você realmente precisar fazer isso, procure usar poucas chamadas "Chunky" (que realiza muitas operações de uma só vez) no lugar de muitas chamadas "Chatty" (que faz poucas operações em uma chamada)

Tipos Blittable

São tipos que possuem a mesma representação tanto na memória gerenciada (runtime .NET) ou não gerenciada. E por isso podem ser copiados através de chamadas entre códigos gerenciados e não gerenciados sem a necessidade de conversão. Os tipos Blittable são:

  • System.Byte

  • System.SByte

  • System.Int16

  • System.UInt16

  • System.Int32

  • System.UInt32

  • System.Int64

  • System.IntPtr

  • System.UIntPtr

Nessa segunda parte, vimos algumas dicas sobre declarações, operações e procedimentos. Na terceira e última parte, veremos algumas dicas sobre o uso do ambiente de desenvolvimento e outras otimizações. Até breve.

Leonardo Bruno Lima
lblima_net@hotmail.com
Microsoft MVP (Most Valuable Professional)
Trabalha com desenvolvimento de aplicações .NET desde 2001. Ministra cursos sobre a plataforma .NET, é consultor de tecnologia e desenvolvedor de sistemas na RR Consultoria e Sistemas (Fortaleza - CE).
Atualmente está dedicado ao desenvolvimento de um sistema ERP utilizando a plataforma .NET

Mostrar: