Desenvolvimento - Visual Basic .NET
.Net Framework Inside : Otimizações do Compilador
Veja as otimizações que o compilador do .NET realiza e como tirar proveito delas.
por Guilherme Bacellar MoralezOs compiladores do .NET Framework implementam uma série de otimizações que são executadas no momento da compilação.
Isso corre para que o programador possa ter mais “clareza” ao ler um fonte e não perder performance durante a execução do mesmo.
Vamos abordar algumas destas otimizações que sendo de nosso conhecimento pode oferecer uma nova abordagem a problemas antigos e facilitar nosso dia a dia como programadores.
Para motivos didáticos os códigos
compilados em C# serão obtidos dos códigos fontes em C# e os códigos compilados
em VB.Net serão obtidos dos códigos fontes em VB.Net, desta forma poderemos
observar se existem diferencias de otimizações entre os compiladores C#.Net e
VB.Net.
Constantes
Se algo é uma constante, então, ele “é o que é” e “será sempre o que é”, imutável em sua própria natureza e preso a sua própria e única existência.
Neste espírito o compilador troca todas as chamadas a uma constante pelo próprio valor da constante, evitando assim chamadas desnecessárias a posições de memória que poderiam (caso não acontece-se a troca) existir com o valor.
Fonte Original em C#
const string csvSeparator = ";";
const string endOfLineSeparator = "\n";
string nome = "Guilherme Bacellar Moralez";
int idade = 25;
string sexo = "Masculino";
string dadoEmCSV = nome + csvSeparator + idade.ToString() + csvSeparator + sexo + endOfLineSeparator;
Fonte Original em VB.Net
Sub Main()
Const csvSeparator As String = ";"
Const endOfLineSeparator As String = vbCrLf
Dim nome As String = "Guilherme Bacellar Moralez"
Dim idade As Integer = 25
Dim sexo As String = "Masculino"
Dim dadoEmCSV As String = nome + csvSeparator + idade.ToString() + csvSeparator + sexo + endOfLineSeparator
End Sub
Resultado Compilado em C#
private static void Main(string[] args)
{
string nome = "Guilherme Bacellar Moralez";
int idade = 0x19;
string sexo = "Masculino";
string dadoEmCSV = nome + ";" + idade.ToString() + ";" + sexo + "\n";
}
Resultado Compilado em VB.Net
Public Shared Sub Main()
Dim nome As String = "Guilherme Bacellar Moralez"
Dim idade As Integer = &H19
Dim sexo As String = "Masculino"
Dim dadoEmCSV As String = String.Concat(New String() {nome, ";", idade.ToString, ";", sexo, ChrW(13) & ChrW(10)})
End Sub
Podemos observar que as variáveis que originalmente eram consideras constantes foram eliminadas do código fonte resultante e suas referências foram trocadas pelos próprios valores atribuídos originalmente às constantes.
Remoção de Itens não Usados
Para falar deste item, deixe-me introduzir uma pergunta: Você manteria o seu lixo em casa?
Acredito veementemente que a resposta um sonoro NÃO!!!!!!!
Bom, nem os compiladores do .NET (Atenção!!!!!, estamos falando neste artigo dos compiladores de C# e VB.NET) fazem isso.
Dentro do ciclo de processamento existe a capacidade de remover variáveis e blocos de código que nunca serão utilizados no programa, então, nada mais natural do que remover estes blocos.
Vamos pegar o exemplo acima e fazer uma leve mudança no código.
Fonte Original em C#
private static void Main(string[] args)
{
const string csvSeparator = ";";
const string endOfLineSeparator = "\n";
string nome = "Guilherme Bacellar Moralez";
int idade = 25;
string sexo = "Masculino";
string dadoEmCSV = nome + csvSeparator + idade.ToString() + csvSeparator + sexo;
if (dadoEmCSV.Equals("Guilherme Bacellar Moralez;25;Masculino"))
{
return;
}
dadoEmCSV += endOfLineSeparator;
}
Fonte Original em VB.Net
Sub Main()
Const csvSeparator As String = ";"
Const endOfLineSeparator As String = vbCrLf
Dim nome As String = "Guilherme Bacellar Moralez"
Dim idade As Integer = 25
Dim sexo As String = "Masculino"
Dim dadoEmCSV As String = nome + csvSeparator + idade.ToString() + csvSeparator + sexo
If (dadoEmCSV.Equals("Guilherme Bacellar Moralez;25;Masculino")) Then
Exit Sub
End If
dadoEmCSV = dadoEmCSV + endOfLineSeparator
End Sub
Resultado Compilado em C#
private static void Main(string[] args)
{
string nome = "Guilherme Bacellar Moralez";
int idade = 0x19;
string sexo = "Masculino";
string dadoEmCSV = nome + ";" + idade.ToString() + ";" + sexo;
if (!dadoEmCSV.Equals("Guilherme Bacellar Moralez;25;Masculino"))
{
dadoEmCSV = dadoEmCSV + "\n";
}
}
Resultado Compilado em VB.Net
Public Shared Sub Main()
Dim nome As String = "Guilherme Bacellar Moralez"
Dim idade As Integer = &H19
Dim sexo As String = "Masculino"
Dim dadoEmCSV As String = String.Concat(New String() {nome, ";", idade.ToString, ";", sexo})
If Not dadoEmCSV.Equals("Guilherme Bacellar Moralez;25;Masculino") Then
dadoEmCSV = (dadoEmCSV & ChrW(13) & ChrW(10))
End If
End Sub
Uma vez detectado que, existe uma linha de código que nunca será utilizada no código fonte, o compilador remove esta linha do Build final. De quebra, foi removida a linha que declarava a constante “endOfLineSeparator”, afinal, o único ponto em que ela seria utilizada nunca será chamado pelo código fonte.
Otimizações Aritméticas
1 + 1 = 2
2 + 2 = 4
((1 + 2) * 3) * (99 / (3 * 4)) = 74,25
Um computador é (no fundo) uma máquina de calcular extremamente sofisticada, então, o que ele sabe fazer de melhor é realizar operações matemáticas.
Da mesma forma os compiladores conseguem realizar otimizações de formulas e cálculos de nosso código para evitar que sejam executadas operações de forma desnecessária.
Fonte Original em C#
private static void Main(string[] args)
{
int idadeInicial = 25;
double modificadorIPrevidencia = 0.69 + 1;
double modificadorIIPrevidencia = 9.9999 - 0.001 ;
double modificadorIIIPrevidencia = modificadorIPrevidencia*modificadorIIPrevidencia;
double valorCotaPrevidencia = 0.2236977;
double totalValorInvestido = 1000000;
double totalCotas;
totalCotas = (totalValorInvestido/valorCotaPrevidencia)* ((modificadorIIPrevidencia/(modificadorIPrevidencia/idadeInicial)))*modificadorIIIPrevidencia;
}
Fonte Original em VB.Net
Sub Main()
Dim idadeInicial As Integer = 25
Dim modificadorIPrevidencia As Double = 0.69 + 1
Dim modificadorIIPrevidencia As Double = 9.9999 - 0.001
Dim modificadorIIIPrevidencia As Double = modificadorIPrevidencia * modificadorIIPrevidencia
Dim valorCotaPrevidencia As Double = 0.2236977
Dim totalValorInvestido As Double = 1000000
Dim totalCotas As Double
totalCotas = (totalValorInvestido / valorCotaPrevidencia) * ((modificadorIIPrevidencia / (modificadorIPrevidencia / idadeInicial))) * modificadorIIIPrevidencia
End Sub
Resultado Compilado em C#
private static void Main(string[] args)
{
int idadeInicial = 0x19;
double modificadorIPrevidencia = 1.69;
double modificadorIIPrevidencia = 9.9989;
double modificadorIIIPrevidencia = modificadorIPrevidencia * modificadorIIPrevidencia;
double valorCotaPrevidencia = 0.2236977;
double totalValorInvestido = 1000000.0;
double totalCotas = ((totalValorInvestido / valorCotaPrevidencia) * (modificadorIIPrevidencia / (modificadorIPrevidencia / ((double)idadeInicial)))) * modificadorIIIPrevidencia;
}
Resultado Compilado em VB.Net
Public Shared Sub Main()
Dim idadeInicial As Integer = &H19
Dim modificadorIPrevidencia As Double = 1.69
Dim modificadorIIPrevidencia As Double = 9.9989
Dim modificadorIIIPrevidencia As Double = (modificadorIPrevidencia * modificadorIIPrevidencia)
Dim valorCotaPrevidencia As Double = 0.2236977
Dim totalValorInvestido As Double = 1000000
Dim totalCotas As Double = (((totalValorInvestido / valorCotaPrevidencia) * (modificadorIIPrevidencia / (modificadorIPrevidencia / CDbl(idadeInicial)))) * modificadorIIIPrevidencia)
End Sub
Observemos que ocorreram algumas otimizações:
· A variável que é inteira foi convertida para notação em Hexadecimal (0x19) representa o número 25.
· As variáveis “modificadorIPrevidencia” e “modificadorIIPrevidencia” tiveram seus valores somados automaticamente pelo compilador e o resultado foi atribuído á variável. De certa forma, esse calculo resulta em um “constante”.
· Observe que a formula matemática foi “levemente” alterada, mas, a alteração visa apenas performance não alterando o resultado final.
Otimizações de Declaração de Variáveis
Código fonte mais “legível” não significa necessariamente código fonte mais lento.
Em diversas ocasiões trabalhei com equipes que me diziam que declarar uma variável e depois atribuir o valor a ela (em linhas diferentes) era mais lento do que declarar a variável e atribuir o valor no momento da declaração.
Nada melhor do que decompilar para aprender, então...
Fonte Original em C#
private static void Main(string[] args)
{
// Declara as Constantes
const string csvSeparator = ";";
const string endOfLineSeparator = "\n";
// Declara as Variáveis
string nome;
int idade;
string sexo;
string dadoEmCSV = "";
string dadoLoop;
// Preenche as Variáveis
sexo = "Masculino";
nome = "Guilherme Bacellar Moralez";
idade = 25;
for (int i = 0; i <= idade; i++)
{
dadoLoop = nome;
dadoLoop += csvSeparator;
dadoLoop += idade.ToString();
dadoLoop += csvSeparator;
dadoLoop += sexo;
dadoLoop += endOfLineSeparator;
dadoEmCSV += dadoLoop;
}
}
Fonte Original em VB.Net
Sub Main()
" Declara as Constantes
Const csvSeparator As String = ";"
Const endOfLineSeparator As String = "\n"
" Declara as Variáveis
Dim nome As String
Dim idade As Integer
Dim sexo As String
Dim dadoEmCSV As String = ""
Dim dadoLoop As String
" Preenche as Variáveis
sexo = "Masculino"
nome = "Guilherme Bacellar Moralez"
idade = 25
For i As Integer = 0 To idade
dadoLoop = nome
dadoLoop += csvSeparator
dadoLoop += idade.ToString()
dadoLoop += csvSeparator
dadoLoop += sexo
dadoLoop += endOfLineSeparator
dadoEmCSV += dadoLoop
Next
End Sub
Resultado Compilado em C#
private static void Main(string[] args)
{
string dadoEmCSV = "";
string sexo = "Masculino";
string nome = "Guilherme Bacellar Moralez";
int idade = 0x19;
for (int i = 0; i <= idade; i++)
{
string dadoLoop = nome;
dadoLoop = ((dadoLoop + ";") + idade.ToString() + ";") + sexo + "\n";
dadoEmCSV = dadoEmCSV + dadoLoop;
}
}
Resultado Compilado em VB.Net
Public Shared Sub Main()
Dim dadoEmCSV As String = ""
Dim sexo As String = "Masculino"
Dim nome As String = "Guilherme Bacellar Moralez"
Dim idade As Integer = &H19
Dim VB$t_i4$L0 As Integer = idade
Dim i As Integer = 0
Do While (i <= VB$t_i4$L0)
Dim dadoLoop As String = nome
dadoLoop = (((dadoLoop & ";") & idade.ToString & ";") & sexo & "\n")
dadoEmCSV = (dadoEmCSV & dadoLoop)
i += 1
Loop
End Sub
Vamos observar atentamente as mudanças realizadas
- As variáveis que foram declaradas e atribuídas posteriormente foram agrupadas;
- A variável “dadoLoop” que foi declarada fora do loop foi transferida pelo compilador para dentro do loop;
- As diversas linhas de concatenação do loop foram substituídas por apenas 1 linha;
Conclusões
A que conclusões podemos chegar:
Bom, eu cheguei a 2 delas:
1-) Existem diversas formas de se obter o mesmo resultado. O compilador otimiza para o melhor resultado.
2-) Código mais “legível” não significa código mais lento.
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET