Compilación ReadyToRun

La latencia y el tiempo de inicio de la aplicación .NET se pueden mejorar si se compilan los ensamblados de aplicación como formato ReadyToRun (R2R). R2R es una forma de compilación Ahead Of Time (AOT).

Los binarios de R2R mejoran el rendimiento de inicio reduciendo la cantidad de trabajo que el compilador Just-In-Time (JIT) debe llevar a cabo cuando se carga la aplicación. Los binarios contienen código nativo similar en comparación con lo que generaría el compilador JIT. Sin embargo, los binarios de R2R son más grandes porque contienen tanto el código de lenguaje intermedio (IL), que sigue siendo necesario para algunos escenarios, como la versión nativa del mismo código. R2R solo está disponible cuando publica una aplicación que tenga como destino entornos de tiempo de ejecución específicos (RID), como Linux x64 o Windows x64.

Para compilar el proyecto como ReadyToRun, la aplicación debe publicarse con la propiedad PublishReadyToRun establecida en true.

Hay dos maneras de publicar la aplicación como ReadyToRun:

  1. Especifique la marca PublishReadyToRun directamente en el comando dotnet publish. Consulte dotnet publish para obtener más información.

    dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true
    
  2. Especifique la propiedad en el proyecto.

    • Agregue el valor <PublishReadyToRun> al proyecto.
    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
    • Publique la aplicación sin ningún parámetro especial.
    dotnet publish -c Release -r win-x64
    

Impacto del uso de la característica ReadyToRun

La compilación anticipada tiene un impacto complejo en el rendimiento de la aplicación, que puede ser difícil de predecir. En general, el tamaño de un ensamblado aumentará entre dos y tres veces. Este aumento en el tamaño físico del archivo puede reducir el rendimiento de la carga del ensamblado desde el disco y aumentar el espacio de trabajo del proceso. Sin embargo, a cambio, el número de métodos compilados en tiempo de ejecución suele reducirse considerablemente. El resultado es que la mayoría de las aplicaciones que tienen grandes cantidades de código obtienen beneficios de rendimiento elevados de la habilitación de ReadyToRun. Las aplicaciones con pequeñas cantidades de código probablemente no experimentarán una mejora significativa por la habilitación de ReadyToRun, ya que las bibliotecas del entorno de ejecución de .NET ya se han precompilado con ReadyToRun.

La mejora de inicio que se describe aquí no solo se aplica al inicio de la aplicación, sino también al primer uso de cualquier código de la aplicación. Por ejemplo, ReadyToRun se puede usar para reducir la latencia de respuesta del primer uso de la API web en una aplicación de ASP.NET.

Interacción con la compilación en capas

El código generado anticipadamente no está tan optimizado como el código generado por JIT. Para solucionar este problema, la compilación en capas reemplazará los métodos de ReadyToRun usados comúnmente con métodos generados por JIT.

¿Cómo se elige el conjunto de ensamblados precompilados?

El SDK precompilará los ensamblados que se distribuyen con la aplicación. En el caso de las aplicaciones independientes, este conjunto de ensamblados incluirá el marco. Los archivos binarios de C++/CLI no son válidos para la compilación de ReadyToRun.

Para excluir ensamblados específicos del procesamiento ReadyToRun, use la lista <PublishReadyToRunExclude>.

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

¿Cómo se elige el conjunto de métodos para la precompilación?

El compilador intentará precompilar todos los métodos que pueda. Aun así, debido a varias razones, no se espera que el uso de la característica ReadyToRun impida la ejecución de JIT. Estos motivos pueden incluir, entre otros, los siguientes:

  • Uso de tipos genéricos definidos en ensamblados independientes
  • Interoperabilidad con código nativo
  • Uso de elementos intrínsecos de hardware que el compilador no puede probar que sean seguros de usar en una máquina de destino
  • Ciertos patrones de IL inusuales
  • Creación de métodos dinámicos mediante reflexión o LINQ

Generación de símbolos para su uso con los generadores de perfiles

Al compilar una aplicación con ReadyToRun, es posible que los generadores de perfiles requieran símbolos para examinar los archivos ReadyToRun generados. Para habilitar la generación de símbolos, especifique la propiedad <PublishReadyToRunEmitSymbols>.

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

Estos símbolos se colocarán en el directorio de publicación y tendrán una extensión de archivo .ni.pdb para Windows y una extensión de archivo .r2rmap para Linux. Por lo general, estos archivos no se redistribuyen a los clientes finales, sino que normalmente se almacenarían en un servidor de símbolos. En general, estos símbolos son útiles para depurar problemas de rendimiento relacionados con el inicio de aplicaciones, ya que la compilación en capas reemplazará el código generado ReadyToRun por código generado dinámicamente. Sin embargo, si se intenta crear perfiles de una aplicación que deshabilita la compilación en capas, los símbolos serán útiles.

Composite ReadyToRun

La compilación ReadyToRun normal genera archivos binarios que se pueden suministrar y manipular individualmente. A partir de .NET 6, se ha agregado compatibilidad con la compilación Composite ReadyToRun. Composite ReadyToRun compila un conjunto de ensamblados que se deben distribuir conjuntamente. Esto tiene la ventaja de que el compilador puede realizar mejores optimizaciones y reduce el conjunto de métodos que no se pueden compilar mediante el proceso ReadyToRun. Sin embargo, como contrapartida, la velocidad de compilación se reduce significativamente y el tamaño total del archivo de la aplicación aumenta notablemente. Debido a estos problemas, el uso de Composite ReadyToRun solo se recomienda para las aplicaciones que deshabilitan la compilación en capas o las aplicaciones que se ejecutan en Linux que buscan el mejor tiempo de inicio con una implementación independiente. Para habilitar la compilación Composite ReadyToRun, especifique la propiedad <PublishReadyToRunComposite>.

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

Nota:

En .NET 6, Composite ReadyToRun solo se admite para la implementación autónoma.

Restricciones multiplataforma y de arquitectura

Para algunas plataformas SDK, el compilador ReadyToRun es capaz de realizar una compilación cruzada para otras plataformas de destino.

Los destinos de compilación admitidos al dirigirse a .NET 6 y versiones posteriores se describen en la tabla siguiente.

Plataforma de SDK Plataformas de destino compatibles
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)

Los destinos de compilación admitidos al dirigirse a .NET 5 y versiones anteriores se describen en la tabla siguiente.

Plataforma de SDK Plataformas de destino compatibles
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