从 .NET 11 开始,该框架将不再运行在缺乏现代指令集的旧硬件上,例如那些需要 x86-64-v1 基准的硬件。这一转变将所有操作系统的最低要求提升至 x86-64-v2,此项更改旨在与 Windows 11 等现代操作系统的硬件要求保持一致,并减少支持旧式处理器的复杂度。

现代化硬件要求

.NET 11 运行时更新了其最低硬件要求,以支持 x86/x64 和 Arm64 架构上的现代指令集。对于 x86/x64 系统,基准从 v1 移至 v2,这保证了对 CX16、POPCNT、SSE3、SSSE3、SSE4.1 和 SSE4.2 等指令集的支持。

显示 .NET 11 更新后的硬件基准要求的表格。
.NET 11 运行时更新其最低硬件要求以与现代操作系统保持一致。learn.microsoft.com

此图展示了硬件现代化部分描述的特定硬件基准转变和指令集要求。

x86/x64 基准更新: 之前的最小值 x86-64-v1; 新的最小值 x86-64-v2
x86/x64 基准更新learn.microsoft.com

图表由 HN Digest 根据 learn.microsoft.com 报告的数据绘制;数值按来源原文显示。

在 Arm64 架构上,该更新为 Windows 和 Linux 引入了对 LSE(大系统扩展)指令集的新要求。特别是对于 Windows,ReadyToRun (R2R) 目标已更新为 armv8.2-a + RCPC,涵盖了操作系统官方支持的大多数硬件。

“更新最低基准是为了降低代码库的维护复杂度,并更好地与底层操作系统的文档要求(且通常是强制要求的硬件要求)保持一致。”

— What's new in .NET 11 runtime

过渡到运行时原生异步

.NET 11 中的一个重大架构转变是引入了“Runtime Async V2”。这一功能摒弃了传统模型,即编译器生成状态机类来处理异步任务。相反,现在由运行时本身来跟踪异步执行、挂起和恢复。

演示 Runtime Async V2 实现的代码片段。
展示向运行时原生异步执行过渡的示例代码。learn.microsoft.com

此截图提供了“Runtime Async V2”功能的具体示例,该功能取代了编译器生成的状态机。

这一变化产生了更清晰的堆栈跟踪,因为在实时执行期间,实际的方法会直接出现在调用堆栈上。它还提高了可调试性,允许调试器在不跳入编译器生成的框架的情况下步入 await 边界。运行时库本身现在已启用此功能进行编译,从而允许整个应用程序更平滑地迁移。

性能和优化收益

新的 Runtime Async 模型包含多项性能优化,例如为返回任务的同步方法提供 JIT 编译的专用版本。JIT 还会尾合并(tail-merge)异步挂起点以减少代码大小,并缓存延续点(continuations)以减少异步密集型代码中的分配压力。

此外,运行时现在可以检测延续点是否没有任何内容需要恢复,并跳过 ExecutionContext 的捕获/恢复周期。这降低了高吞吐路径中的开销,特别是对于那些少量使用 AsyncLocal 值并调用 ConfigureAwait(false) 的应用程序。

维护与兼容性权衡

微软表示,转向更高的硬件基准通过移除不太可能使用的旧硬件支持,降低了代码库的复杂度。这还有助于为 AOT 目标定义“最低公分母”,通过避免默认使用最旧的指令集来提高性能。

然而,这意味着目标为 .NET 11 的应用程序将无法在旧 CPU 上运行,可能会打印一条消息指出 CPU 缺少基准指令集。对于支持 ReadyToRun 的程序集,某些不符合新预期支持要求的支持硬件可能会经历额外的启动开销。

Hacker News 读者的反应

  • 技术补充: 一位评论者指出处理 decimal 的特定变化,注意到在 .NET 11 中,0.1 的值与 .NET 10 相比具有不同的表示方式。 评论 ↗
  • 技术补充: 一位用户对运行时异步支持表示惊讶,指出虽然他们预期堆栈跟踪会改善,但他们对该变化仍能保持同等性能感到印象深刻。 评论 ↗
  • 技术补充: 一位评论者提出了关于运行时异步底层实现的一个开放问题,询问这是否意味着使用 stackful 协程。 评论 ↗
  • 技术补充: 一位评论者澄清 .NET 11 是标准期限支持(Standard Term Support)版本,指出它实际上比 .NET 10 拥有更短的支持窗口。 评论 ↗

以上为 Hacker News 讨论中观点的摘要,并非经过核实的事实。 阅读完整讨论 ↗