Компиляция ReadyToRun

Вы можете уменьшить время запуска и задержку приложения .NET, скомпилировав все сборки приложения в формат ReadyToRun (R2R). R2R является разновидностью компиляции AOT.

Бинарные файлы R2R повышают производительность при запуске, снижая объем работы, выполняемой на этом этапе компилятором JIT. Бинарные файлы содержат такой же машинный код, который создается компилятором JIT. Но бинарные файлы R2R имеют больший размер, так как содержат не только код на промежуточном языке (IL), который по-прежнему необходим для некоторых сценариев, но и версию того же кода на машинном языке. Функция R2R доступна только при публикации приложения, предназначенного для конкретной среды выполнения (RID), например для Windows x64 или Linux x64.

Чтобы скомпилировать проект в формат ReadyToRun, нужно опубликовать приложение, задав свойство PublishReadyToRun со значением true.

Опубликовать приложение в формате ReadyToRun можно двумя способами:

  1. Укажите флаг PublishReadyToRun непосредственно для команды dotnet publish. Дополнительные сведения см. в статье dotnet publish.

    dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true
    
  2. Укажите свойство в проекте.

    • Добавьте параметр <PublishReadyToRun> в проект.
    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
    • Опубликуйте приложение без особых параметров.
    dotnet publish -c Release -r win-x64
    

Влияние использования функции ReadyToRun

Компиляция Ahead Of Time оказывает существенное влияние на производительность приложения, которую может быть трудно спрогнозировать. Как правило, размер сборки увеличивается в два или три раза. Увеличение физического размера файла может привести к снижению производительности при загрузке сборки с диска и увеличить рабочий набор процесса. Но при этом число методов, компилируемых во время выполнения, обычно значительно сокращается. В результате большинство приложений с большим объемом кода получают значительные преимущества в отношении производительности, если включена функция ReadyToRun. Для приложений с небольшим объемом кода, скорее всего, будет трудно заметить значительное улучшение работы, когда функция ReadyToRun включена, так как библиотеки среды выполнения .NET были предварительно скомпилированы с помощью ReadyToRun.

Такое улучшение относится не только к запуску приложений, но и к первому использованию любого кода в приложении. Например, с помощью ReadyToRun можно уменьшить задержку ответа при первом использовании веб-API в приложении ASP.NET.

Взаимодействие с многоуровневой компиляцией

Код, созданный при компиляции Ahead Of Time, не так хорошо оптимизирован как код, созданный JIT-компилятором. Для решения этой проблемы в многоуровневой компиляция часто используемые методы ReadyToRun заменяются методами, созданными JIT-компилятором.

Как выбирается набор предварительно скомпилированных сборок

Пакет SDK реализует предварительную компиляцию сборок, распространяемых вместе с приложением. Для автономных приложений в такой набор сборок будет включена платформа. Двоичные файлы C++/CLI не подходят для компиляции ReadyToRun.

Чтобы исключить определенные сборки из обработки ReadyToRun, используйте список <PublishReadyToRunExclude>.

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

Как выбирается набор методов для предварительной компиляции

Компилятор попытается предварительно скомпилировать как можно больше методов. Но по ряду причин использование функции ReadyToRun вряд ли помешает JIT-компиляции. Помимо прочего, к таким причинам могут относиться:

  • использование универсальных типов, определенных в отдельных сборках;
  • взаимодействие с машинным кодом;
  • использование встроенных аппаратных средств, безопасность которых компилятор не может гарантировать для целевого компьютера;
  • некоторые нестандартные шаблоны IL;
  • динамическое создание методов с использованием отражения или LINQ.

Создание символов для использования с профилировщиками

При компиляции приложения с помощью ReadyToRun, профилировщикам могут потребоваться символы для проверки созданных файлов ReadyToRun. Чтобы включить создание символов, укажите свойство <PublishReadyToRunEmitSymbols>.

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

Эти символы будут помещены в каталог публикации и для Windows будут иметь расширение файла. ni.pdb, а для Linux — .r2rmap. Обычно эти файлы не распространяются для конечных клиентов и хранятся на сервере символов. В целом, эти символы полезны для отладки проблем с производительностью, связанных с запуском приложений, так как многоуровневая компиляция заменит созданный код ReadyToRun динамически создаваемым кодом. Однако при попытке профилирования приложения, в котором отключена многоуровневая компиляция, символы будут полезны.

Составной ReadyToRun

При обычной компиляции ReadyToRun создаются двоичные файлы, которые можно обслуживать и обрабатывать по отдельности. Начиная с .NET 6 добавлена поддержка составной компиляции ReadyToRun. Составной процесс ReadyToRun компилирует набор сборок, которые должны распространяться вместе. Это позволяет компилятору выполнять более эффективную оптимизацию и сокращает набор методов, которые не могут быть скомпилированы с помощью процесса ReadyToRun. Однако при этом значительно снижается скорость компиляции, а общий размер файла приложения существенно увеличивается. Из-за этих компромиссов использование составного процесса ReadyToRun рекомендуется только для приложений с отключенной многоуровневой компиляцией или приложений, работающих в Linux, которым требуется лучшее время запуска с автономным развертыванием. Чтобы включить составную компиляцию ReadyToRun, укажите свойство <PublishReadyToRunComposite>.

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

Примечание

В .NET 6 составной ReadyToRun поддерживается только для автономного развертывания.

Ограничения при работе с несколькими платформами и архитектурами

На некоторых платформах SDK компилятор ReadyToRun может выполнять перекрестную компиляцию для других целевых платформ.

В следующей таблице перечислены целевые объекты компиляции, которые поддерживаются при нацеливании на .NET 6 и более поздних версий.

SDK платформы Поддерживаемые целевые платформы
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)

Поддерживаемые целевые объекты компиляции описаны в таблице ниже при ориентации на .NET 5 и более ранних версий.

SDK платформы Поддерживаемые целевые платформы
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