Compilação ReadyToRun

O tempo de inicialização e a latência do aplicativo .NET podem ser melhorados compilando os assemblies do aplicativo no formato ReadyToRun (R2R). R2R é uma forma de compilação ahead-of-time (AOT).

Os binários R2R melhoram o desempenho de inicialização reduzindo a quantidade de trabalho que o compilador just-in-time (JIT) precisa fazer enquanto seu aplicativo é carregado. Os binários contêm código nativo semelhante em comparação com o que o JIT produziria. No entanto, os binários R2R são maiores porque contêm código de linguagem intermediária (IL), que ainda é necessário para alguns cenários, e a versão nativa do mesmo código. O R2R só está disponível quando você publica um aplicativo destinado a ambientes de tempo de execução específicos (RID), como Linux x64 ou Windows x64.

Para compilar seu projeto como ReadyToRun, o aplicativo deve ser publicado com a propriedade PublishReadyToRun definida como true.

Há duas maneiras de publicar seu aplicativo como ReadyToRun:

  1. Especifique o sinalizador PublishReadyToRun diretamente para o comando dotnet publishing. Consulte dotnet publish para obter detalhes.

    dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true
    
  2. Especifique a propriedade no projeto.

    • Adicione a <PublishReadyToRun> configuração ao seu projeto.
    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
    • Publique o aplicativo sem parâmetros especiais.
    dotnet publish -c Release -r win-x64
    

Impacto do uso do recurso ReadyToRun

A compilação antecipada tem um impacto complexo no desempenho do aplicativo, que pode ser difícil de prever. Em geral, o tamanho de um conjunto aumentará para entre duas a três vezes maior. Esse aumento no tamanho físico do arquivo pode reduzir o desempenho de carregar o assembly do disco e aumentar o conjunto de trabalho do processo. No entanto, em troca, o número de métodos compilados em tempo de execução é normalmente reduzido substancialmente. O resultado é que a maioria dos aplicativos que têm grandes quantidades de código recebem grandes benefícios de desempenho ao habilitar o ReadyToRun. Os aplicativos que têm pequenas quantidades de código provavelmente não experimentarão uma melhoria significativa ao habilitar o ReadyToRun, pois as bibliotecas de tempo de execução do .NET já foram pré-compiladas com o ReadyToRun.

A melhoria de inicialização discutida aqui se aplica não apenas à inicialização do aplicativo, mas também ao primeiro uso de qualquer código no aplicativo. Por exemplo, o ReadyToRun pode ser usado para reduzir a latência de resposta do primeiro uso da API da Web em um aplicativo ASP.NET.

Interação com compilação hierárquica

O código gerado antecipadamente não é tão altamente otimizado quanto o código produzido pelo JIT. Para resolver esse problema, a compilação hierárquica substituirá os métodos ReadyToRun comumente usados por métodos gerados por JIT.

Como é escolhido o conjunto de montagens pré-compiladas?

O SDK pré-compilará os assemblies que são distribuídos com o aplicativo. Para aplicativos autônomos, esse conjunto de assemblies incluirá a estrutura. Os binários C++/CLI não são elegíveis para a compilação ReadyToRun.

Para excluir assemblies específicos do processamento ReadyToRun, use a <PublishReadyToRunExclude> lista.

<ItemGroup>
  <PublishReadyToRunExclude Include="Contoso.Example.dll" />
</ItemGroup>

Como é escolhido o conjunto de métodos para pré-compilar?

O compilador tentará pré-compilar tantos métodos quanto puder. No entanto, por vários motivos, não é esperado que o uso do recurso ReadyToRun impeça a execução do JIT. Tais razões podem incluir, mas não estão limitadas a:

  • Utilização de tipos genéricos definidos em montagens separadas.
  • Interoperabilidade com código nativo.
  • Uso de intrínsecas de hardware que o compilador não pode provar que são seguras para uso em uma máquina de destino.
  • Certos padrões incomuns de IL.
  • Criação de métodos dinâmicos via reflexão ou LINQ.

Geração de símbolos para uso com criadores de perfil

Ao compilar um aplicativo com ReadyToRun, os criadores de perfil podem exigir símbolos para examinar os arquivos ReadyToRun gerados. Para habilitar a geração de símbolos, especifique a <PublishReadyToRunEmitSymbols> propriedade.

<PropertyGroup>
  <PublishReadyToRunEmitSymbols>true</PublishReadyToRunEmitSymbols>
</PropertyGroup>

Esses símbolos serão colocados no diretório de publicação e para Windows terá uma extensão de arquivo .ni.pdb, e para Linux terá uma extensão de arquivo de .r2rmap. Esses arquivos geralmente não são redistribuídos para os clientes finais, mas normalmente seriam armazenados em um servidor de símbolos. Em geral, esses símbolos são úteis para depurar problemas de desempenho relacionados à inicialização de aplicativos, pois a compilação hierárquica substituirá o código gerado pelo ReadyToRun por código gerado dinamicamente. No entanto, se tentar criar o perfil de um aplicativo que desativa a compilação hierárquica, os símbolos serão úteis.

ReadyToRun composto

A compilação ReadyToRun normal produz binários que podem ser atendidos e manipulados individualmente. A partir do .NET 6, foi adicionado suporte para a compilação Composite ReadyToRun. Composite ReadyToRun compila um conjunto de assemblies que devem ser distribuídos juntos. Isso tem a vantagem de que o compilador é capaz de executar melhores otimizações e reduz o conjunto de métodos que não podem ser compilados através do processo ReadyToRun. No entanto, como compensação, a velocidade de compilação é significativamente reduzida e o tamanho geral do arquivo do aplicativo é significativamente aumentado. Devido a essas compensações, o uso do Composite ReadyToRun só é recomendado para aplicativos que desabilitam a compilação hierárquica ou aplicativos em execução no Linux que estão buscando o melhor tempo de inicialização com implantação independente . Para habilitar a compilação composta ReadyToRun, especifique a <PublishReadyToRunComposite> propriedade.

<PropertyGroup>
  <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>

Nota

No .NET 6, o Composite ReadyToRun só é suportado para implantação independente .

Restrições entre plataformas/arquitetura

Para algumas plataformas SDK, o compilador ReadyToRun é capaz de compilação cruzada para outras plataformas de destino.

Os destinos de compilação suportados são descritos na tabela abaixo ao direcionar o .NET 6 e versões posteriores.

Plataforma SDK Plataformas de destino suportadas
Windows X64 Windows (X86, X64, Arm64), Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
Windows X86 Windows (x86), Linux (Arm32)
Linux X64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
Linux Arm32 Linux Arm32
Linux Arm64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
macOS X64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
macOS Arm64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)

Os destinos de compilação suportados são descritos na tabela abaixo ao direcionar o .NET 5 e abaixo.

Plataforma SDK Plataformas de destino suportadas
Windows X64 Windows X86, Windows X64, Windows Arm64
Windows X86 Windows X86, Windows Arm32
Linux X64 Linux X86, Linux X64, Linux Arm32, Linux Arm64
Linux Arm32 Linux Arm32
Linux Arm64 Linux Arm64
macOS X64 macOS X64