ReadyToRun 編譯

您可以將應用程式組件編譯為 ReadyToRun (R2R) 格式,以改善 .NET 應用程式啟動時間和延遲。 R2R 是一種預先(AOT) 編譯。

R2R 二進位檔會透過減少 Just-In-Time (JIT) 編譯器在應用程式載入時所需執行的工作量,來改善啟動效能。 二進位檔包含的機器碼,與 JIT 所會產生的內容類似。 但是,R2R 二進位檔大小較大,因為它們會同時包含中繼語言 (IL) 程式碼 (在某些案例下仍需要使用),以及相同程式碼的原生版本。 R2R 只有在您發佈以特定執行階段環境 (RID) (例如 Linux x64 或 Windows 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 功能的影響

預先編譯會對應用程式效能造成複雜的效能影響,且可能難以預測。 一般而言,組件的大小會增長到兩到三倍之間。 這會增加檔案的實體大小,可能會降低從磁碟載入組件的效能,並增加進程的工作集。 不過,反過來傳回在執行階段編譯的方法數目通常會大幅減少。 結果就是大部分具有大量程式碼的應用程式都會收到啟用 ReadyToRun 的大型效能優勢。 由於 .NET 執行階段程式庫已使用 ReadyToRun 預先編譯,因此,具有少量程式碼的應用程式可能無法從啟用 ReadyToRun 中大幅改善。

這裡討論的啟動改進不僅能套用至應用程式啟動,也適用於應用程式中第一次使用任何程式碼。 例如,ReadyToRun 可用來減少 ASP.NET 應用程式中第一次使用 Web API 的回應延遲。

與階層式編譯的互動

預先產生的程式碼不如 JIT 所產生的程式碼經過高度最佳化處理。 為了解決此問題,階層式編譯會以 JIT 產生的方法取代常用的 ReadyToRun 方法。

如何選擇一組先行編譯的組件?

SDK 會先行編譯與應用程式一起散發的組件。 針對獨立式應用程式,這份組件會包含架構。 C++/CLI 二進位檔不符合 ReadyToRun 編譯資格。

若要從 ReadyToRun 處理中排除特定組件,請使用 <PublishReadyToRunExclude> 清單。

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

如何選擇預先編譯一組方法?

編譯器會嘗試盡可能預先編譯許多方法。 不過,基於各種原因,使用 ReadyToRun 功能預期不會防止 JIT 執行。 這些原因包括但不限於:

  • 使用不同的組件中定義的泛型型別。
  • 使用機器碼的 Interop。
  • 使用編譯器無法證明目的電腦上使用的硬體內建函式是安全的。
  • 某些不尋常的 IL 模式。
  • 透過反映或 LINQ 建立動態方法。

用於分析工具的符號產生

使用 ReadyToRun 編譯應用程式時,分析工具可能需要符號來檢查產生的 ReadyToRun 檔案。 若要啟用符號產生,請指定 <PublishReadyToRunEmitSymbols> 屬性。

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

這些符號會放置在發行目錄中,而 Windows 的副檔名過為 .ni.pdb,Linux 的副檔名將為 .r2rmap。 這些檔案通常不會轉散發給終端客戶,通常會儲存在符號伺服器中。 一般而言,這些符號對於偵錯與啟動應用程式相關的效能問題很有用,因為階層式編譯會將 ReadyToRun 產生的程式碼取代為動態產生的程式碼。 不過,如果嘗試分析停用階層式編譯的應用程式,符號將會很有用。

複合 ReadyToRun

一般 ReadyToRun 編譯會產生可個別服務及操作的二進位檔。 從 .NET 6 開始,已新增複合 ReadyToRun 編譯的支援。 複合 ReadyToRun 會編譯一組必須一起散發的組件。 優點是能讓編譯執行更好的最佳化,並減少無法透過 ReadyToRun 程序編譯的方法集合。 不過,取捨就是編譯速度會大幅減少,而且應用程式的整體檔案大小會大幅增加。 由於這些取捨,建議僅針對停用 階層式編譯 的應用程式,或於 Linux 上執行的應用程式,使用復合 ReadyToRun,以尋求獨立式部署的最佳啟動時間。 若要啟用複合 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