Como garantir ótima performance em nossas aplicações, em um cenário onde o código assembly é gerado “on-the-fly“, sem comprometer o tempo de carga de aplicações?
Esse foi o desafio enfrentado pelo time do .NET Core que tem, agora, uma boa solução.
O problema
Em .NET, todos os métodos são compilados na primeira vez em que são executados. Isso pode ser comprovado depurando a execução do código Assembly (usando, por exemplo, WinDBG).
O “problema”, é que cada método era, até então, compilado de uma única vez. O JIT (Just-In-Time) poderia fazer uma otimização muito agressiva, garantindo ótimo desempenho futuro, porém aumentando o tempo da primeira compilação. Outra alternativa, o JIT fazer uma compilação menos “criteriosa”, mais rápida, mas menos eficiente. O impacto mais percebido é no tempo de inicialização de uma aplicação, visto que é quando um grande número de métodos está sendo executado pela primeira vez.
O trade-off é entre inicialização mais rápida e melhor performance futura.
A solução
A solução encontrada pela Microsoft consiste em “compilar” um mesmo método mais de uma vez. Em um primeiro momento, usando algoritmos de compilação mais simples e que são executados em menos tempo, reduzindo o impacto sobre a inicialização da aplicação.
Mais tarde, com a aplicação “de pé”, o JIT repete o processo, considerando inclusive “aprendizados” da primeira compilação deixando o código incrementalmente mais eficiente. Ou seja, um mesmo método passa a ser compilado múltiplas vezes, até atingir condição ideal, com “trocas” a quente.
A compilação em camadas no .NET Core 3 vem como default, pois, garante um melhor desempenho, mas você pode desabilitá-lo em seu projeto, alterando a configuração como abaixo.
<TieredCompilation>false</TieredCompilation>
Qual opção é melhor para sua aplicação?