.NET - Dicas para boas práticas de programação - Desempenho
A seguir algumas dicas de boas práticas de programação retirados do : Manual do Desenvolvedor .NET - Microsoft Consulting Services. Resolvi publicar para incentivar a leitura. Então leia...
Dicas de Desempenho -
Turbinando o código VB.NET
1- Certifique-se que o código que será colocado em produção seja
compilado com a opção de suporte a debug
desabilitada.
2- Habilite a opção Enable Optimizations (menu
Configuration Properties | Optimizations page) da caixa de
diálogo Project Properties.
3- Sempre que possível, crie métodos que não possam ser
reescritos (overridable). Ou seja, não use indiscriminadamente o
modificador Overridable. Um método selado (aquele que não pode
ser reescrito é, em média, 35% mais rápido) deve ser sempre
preferido quando a questão for desempenho.
Exemplo:
Class Teste ' Este método pode ser reescrito Overridable Sub Procedimento() 'Código End Sub ' Método que não pode ser reescrito Private Sub Interno() 'Código End Sub ' Método que não pode ser reescrito Public Sub Externo() 'Código End Sub End Class |
4- Chame métodos diretamente na interface principal da classe.
Métodos chamados via interfaces secundárias serão de quatro a
cinco vezes mais lentos.
5- Evite repetições de Strings. Em aplicações acessadas por
vários usuários, podem existir várias instâncias simultâneas
na memória que carregam várias duplicações de string para a
memória. Use shared member ou string intern pool para evitar o
uso desnecessário de memória e garbage collectors.
Segue abaixo um exemplo de código para a implementação de uma
propriedade para string de conexão que faz uso do string intern
pool, evitando a duplicação de strings.
Exemplo:
' O membro
privado Dim m_ConnString As String Property ConnectionString() As String Get Return m_ConnString End Get Set(ByVal Value As String) m_ConnString = String.Intern(Value) End Set End Property |
6- Codifique destrutores implementando um método Finalize para liberar recursos que não são automaticamente gerenciados pelo .NET Framework (exemplos: Clipboard, arquivos, conexões com base de dados, etc) Em .NET, não existe o evento Terminate; porém, é possível implementar o método Finalize (protected). Esse será automaticamente chamado pelo .NET Framework sempre que o objeto estiver prestes a ser destruído pelo garbage collector. Exemplo:
Class TesteObject ' põe o coletor de lixo sobre pressão Dim dummyArr(1000) As Byte Sub New() OpenClipboard(0) End Sub Protected Overrides Sub Finalize() ' fecha o clipboard quando finalizar CloseClipboard() MyBase.Finalize() End Sub End Class |
Outra solução que aumenta ainda mais o desempenho, mas que acarreta um pouco mais de disciplina é implementar o método Dispose através da interface Idisposable. Esse método conterá o mesmo tipo de código que o método Finalize teria e deverá ser chamado diretamente por clientes antes de atribuir nothing ao objeto. Exemplo:
Class TestObject Implements IDisposable Public Sub Dispose() _ Implements IDisposable.Dispose ' fecha o clipboard CloseClipboard() ' Não é necessário finalizar este objeto GC.SuppressFinalize(Me) End Sub ' o resto do código como era no original... End Class |
O código que deve ser escrito no cliente é:
Dim o As TestObject Try ' cria o objeto o = New TestObject() Finally ' roda o código de limpeza final e o destrói o.Dispose() o = Nothing End Try |
7- Ao escrever código que faça uso de classes/objetos que disparam eventos, dê preferência para utilizar a nova técnica disponível em .NET de fazer, em run time, a atribuição (link) de um evento a um método chamado quando este for disparado. Note que, com a nova técnica, é possível fazer o link do evento com o método de tratamento (event handler) e desfazê-lo. Exemplo:
Dim o As New TestObject Sub UseDynamicEvents() ' associa o evento com a procedure local AddHandler o.TestEvent, AddressOf MyHandler ' usa o objeto (agora MyHandler suporta os eventos) ' ... ' remove o tratador do evento RemoveHandler o.TestEvent, AddressOf MyHandler End Sub Sub MyHandler() ' ...rotina que trata o evento aqui. End Sub |
8- Não use o tradicional
WithEvents que, embora continue sendo
suportado no VB.NET, tem menor desempenho.
Exemplo:
' Pode ser usada a declaração New com
WithEvents Dim WithEvents obj As New TestObject Sub obj_TestEvent() Handles obj.TestEvent ' ..Trata o evento aqui End Sub |
9- Evite disparar exceções desnecessariamente em seu código. Sobretudo ao criar componentes chamados por outros componentes, tente reduzir a probabilidade de uma exceção para zero. Contra-exemplo:
Dim rand As New Random() Sub CanThrowException(ByVal prob As Double) If rand.NextDouble <= prob Then Throw New System.Exception() End If End Sub |
A rotina acima pode disparar uma exceção e isso deverá ser tratado na camada cliente da seguinte forma:
Dim i As Integer Dim prob As Double = 0.01 For i = 1 To 1000000 Try CanThrowException(prob) Catch ' Não faz nada neste caso End Try Next |
Abaixo segue um exemplo de código alternativo que terá um desempenho muito superior:
Function DoesntThrowException(
ByVal prob As Double) As Boolean If rand.NextDouble <= prob Then Return False ' notifica a falha Else Return True ' notifica o sucesso End If End Function |
Observação: Não é a inclusão dos operadores
Try
Catch
que onera o desempenho do código e, sim, o disparar de uma
exceção.
10- Ao concatenar strings repetidas vezes, use o objeto
StringBuilder
(System.Text.StringBuilder). Isso evitará que a cada alteração
da string seja alocada um novo bloco de memória.
Exemplo:
Criando uma lista de 500 numeros separados por virgula Dim sb As New System.Text.StringBuilder(2000) Dim i As Integer For i = 1 To 500 sb.Append(CStr(i)) sb.Append(", ") Next Dim s As String = sb.ToString armazena o resultado em s |
Para máxima performance, instancie o StringBuilder com tamanho
igual ou maior que a quantidade máxima de caracteres a ser
armazenada e nunca re-aproveite o objeto após a extração da
string com o uso do método ToString.
Observação: a antiga técnica de se utilizar uma string grande
fixa e usar a função MID em .NET não é mais adequada pois, a
cada chamada, é alocada uma nova área de memória.
11- Sempre que possível, dê preferência por usar value types.
Porém, evite-os quando existir a necessidade de atribuir um value type a uma variável de objeto (isso causará uma
operação de boxing). Quando atribuir um objeto a um value type, faça uso da chamada de um método, no objeto, que
retorne apenas o valor desejado (isso evitará unboxing).
Lembre-se de que todos os tipos de dados em .NET podem ser
agrupados em:
Value types (tipos Numéricos, Datas, char, structures, enum)
ou Reference types (strings, arrays, classes)
Agora é por em prática para garantir um código mais robusto e elegante.
José Carlos Macoratti