.NET 8 是一个长期支持(LTS) 版本。这篇文章涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8 预览版和发布候选版本将每月交付一次。像往常一样,最终版本将在 11 月的某个时候在 .NET Conf 上发布。
.NET 版本包括产品、库、运行时和工具,代表 Microsoft 内外多个团队之间的协作。这篇博文中涵盖的更广泛的主题并不包含 .NET 8 的所有关键场景和投资。它们代表了很大的领域,但只是进入 .NET 8 的所有重要工作的一部分。我们计划对 ASP.NET Core, Blazor, EF Core, WinForms, WPF 和其他平台进行广泛的投资。
欢迎使用 .NET 8
去年年底,我们发布了 .NET 7,这是 .NET 团队与支持该版本的令人惊叹的社区合作的结果,该版本有10,000多名社区成员提供了超过28,000个社区贡献。.NET 7 是当今构建应用程序的首选框架。该版本将平台与对 ARM64 的原生支持和对 Linux 的增强支持统一起来。它有助于通过 .NET MAUI 等工具使您的应用程序现代化,这些工具可以从同一代码库构建跨平台的移动和桌面应用程序。它包括对 API 性能的改进,并使构建和部署分布式云原生应用程序变得更加容易。. NET 7 通过改进 C# 11 减少了必要的代码量,简化了构建应用程序的体验,并使得仅用几行代码就可以创建和配置 API。从帮助调试云 API 集成到直接从 .NET SDK 构建容器的开发隧道,对工具进行了大量改进,帮助开发人员提高工作效率。
我们将在整个版本中更新 .NET 8 中的新增功能。
您可以通过向下滚动阅读我们在预览1中发布的内容。首先,让我们展望一下 .NET 8 的愿景。
云原生开发者的最佳平台和工具
我们相信 .NET 开发人员应该能够将他们的应用程序快速迁移到云中,在不影响性能的情况下扩展他们的应用程序,并根据可操作的数据和关于您的应用程序在生产中的反馈来改进他们的应用程序。我们将投资于通过持续集成和部署更轻松地管理本地开发和测试的完整端到端体验。我们的目标是让微服务架构的实施以及容器的构建和部署变得更加容易。
云原生是一个术语,用于描述专门为在云计算环境中部署而构建的应用程序的架构和设计。云原生背后的主要思想是利用云计算平台提供的优势,例如可扩展性、弹性和自我修复,来创建高度可扩展和有弹性的应用程序。这提供了灵活性,并避免了为支持增长而对硬件和软件进行潜在的过度投资。许多开发人员将云原生与微服务、容器编排 (Kubernetes) 和“即服务”产品等概念联系在一起。
使用 MAUI 和 Blazor 混合进行跨平台移动和桌面开发的绝佳体验
在 .NET 7 期间,我们发布了 .NET 多平台应用程序用户界面 (MAUI) SDK 和 Visual Studio 工具支持。.NET MAUI 提供了一个框架,用于使用单个 C# 代码库为运行 Android、iOS、macOS 和 Windows 的移动和桌面设备创建本机应用程序。除了支持 XAML UI 之外,您还可以使用 Blazor 构建具有 Razor UI 组件的混合应用程序,这些应用程序可以访问本机设备平台并在移动、桌面和 Web 之间共享。.NET 团队计划以这些经验为基础,专注于提高 SDK 和工具的质量、稳定性、性能和集成度。
势头:根据您的意见继续关注质量和性能
.NET 的每个版本都包括对 API、库和框架的性能、质量、稳定性和易用性的改进,它们构成了活跃且不断发展的 .NET 生态系统。其中许多改进是由客户和社区成员确定并优先考虑的。.NET 8 将遵循相同的趋势,依靠您高度重视的反馈来帮助指导我们的愿景并推动我们的重点。
了解最新情况并保持最新状态
.NET 升级帮助是一个有价值的工具,可以帮助开发人员将他们的应用程序从旧版本的 .NET Framework 迁移到新版本。该工具的最新版本具有改进的功能,可以支持新场景并处理更多案例。有了这个工具,开发人员现在可以轻松地将他们的应用程序升级到 .NET 6或 .NET 7。
该工具可以自动检测并建议需要对代码进行的更改,以确保与较新版本的框架兼容。此外,它还可以处理更复杂的场景,例如升级使用第三方库的应用程序以及与更新的平台功能集成。这些改进使 .NET 升级辅助成为那些希望保持其应用程序最新并利用最新的 .NET 功能的开发人员的不可或缺的工具。该工具最近作为 Visual Studio 扩展引入。可帮助您从舒适的 Visual Studio 升级。
以 .NET 8 为目标
要以 .NET 8 为目标,您首先需要确保从 Microsoft 官方网站安装了 .NET 8 SDK。接下来,您可以创建一个新项目,并通过在项目设置中设置适当的目标框架来指定您希望以 .NET 8 为目标。
您还可以通过更改项目属性中的目标框架,将现有项目更新为面向 .NET 8。为此,请在 Visual Studio 或您喜欢的 IDE 中右键单击项目,选择“属性”,然后选择“应用程序”选项卡。从那里,您可以选择要使用的目标框架版本。这将设置适当的目标框架:
<TargetFramework>net8.0</TargetFramework>
请记住,以 .NET 8 为目标可能需要更改您的代码或依赖项,因为 API 或其他功能可能与以前版本的 .NET 有所不同。最好查看 .NET 8 的文档和发行说明,以确保您的代码和依赖项与新版本兼容。
.NET 8 预览版 1 中的新增功能
我们的第一个预览版包含您今天就可以试用的新功能。以下是预期结果的摘要。有关详细的发行说明和重大更改,请阅读 .NET 8 中的新增功能。
Native AOT
第一个 NativeAOT 功能在 .NET 7 和目标控制台应用程序中发布。Ahead-of-Time (AOT)编译是 .NET 中的一项重要功能,可以对 .NET 应用程序的性能产生重大影响。感谢 Adeel 和 Filip 将 NativeAOT 功能引入 macOS 进行预览 1。.NET 团队将专注于完善 .NET 8 的一些基础知识,例如大小(请参阅dotnet/runtime#79003)。使用 NativeAOT 发布应用程序会创建一个完全独立的应用程序版本,不需要单独的运行时,因为所有内容都包含在单个文件中。从预览版1开始,这个文件变小了。事实上,Linux 版本现在最多缩小了 50%。
以下是包含整个 .NET 运行时的 Native AOT 的“Hello, World”应用程序的大小:
NativeAOT 将继续扩展并瞄准 .NET 8 中的其他应用场景,因此请继续关注此博客以获取未来更新!
如果您不熟悉 AOT,这里有一些 AOT 提供的好处:
- 减少内存占用:与 JIT 编译代码相比,AOT 编译代码需要更少的内存,因为 JIT 编译器生成 AOT 编译应用程序不需要的中间代码。这对于内存有限的设备尤其有益,例如嵌入式系统和移动设备。
- 改进的启动时间:与 JIT 编译代码相比,AOT 编译代码启动速度更快,因为它消除了 JIT 编译器生成中间代码并针对特定硬件和软件环境优化代码的需要。这对于必须快速启动的应用程序尤其有利,例如系统服务、无服务器“功能”和后台任务。
- 延长电池寿命:与 JIT 编译代码相比,AOT 编译代码消耗的电量更少,因为它消除了 JIT 编译器生成中间代码并针对特定硬件和软件环境优化代码的需要。这对于依赖电池的设备(例如移动设备)尤其有益。
.NET 容器镜像
.NET 开发人员可以使用容器镜像以轻量级、可移植的格式打包和部署他们的应用程序,这种格式可以在不同环境中运行并且可以轻松部署到云端中。关于如何将容器镜像用于 .NET 应用程序,预览版 1 做出了以下改进:
- 将默认 Linux 发行版更新为 Debian 12:.NET 容器镜像现在使用 Debian 12 (Bookworm),我们预计将在 2023 年年中发布。Debian 用于方便的标签,8.0如8.0-bookworm-slim。
- 标签更改:.NET 8 预览容器镜像将使用8.0-preview 作为标签(不是8.0)并在 Release Candidate 版本过渡到8.0。这种方法的目标是更清楚地描述预览版。这是根据社区请求进行的更改。
- 与非根(non-root)用户一起运行容器镜像:尽管容器基础镜像几乎总是配置为与根用户一起运行——这种设置往往会保留在生产环境中——但它并不总是最好的方法。然而,将每个应用程序配置为拥有不同的用户是一件很痛苦的事情,而且容器镜像不会附带适合容器工作负载的非根用户。
.NET 8 提供了一种更好的方法。从预览版 1 开始,我们发布的所有容器镜像都将支持非根配置。以下是用于以非根身份为 Dockerfiles 运行容器的单行示例:
USER app
此外,您现在可以使用 -u app。默认端口已从端口80更改为8080。这是启用非根方案所必需的重大更改,因为端口80是特权端口。
运行时和库
处理随机性的实用方法
System.Random 和 System.Security.Cryptography.RandomNumberGenerator 都有实用方法 GetItems 以用于从输入集中随机选择项目(“用替换”),以及用于随机化跨度顺序的实用方法 Shuffle。
Shuffle 有助于减少机器学习中的训练偏差(因此第一件事并不总是训练,最后一件事总是测试):
YourType[] trainingData = LoadTrainingData();
Random.Shared.Shuffle(trainingData);
IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData);
DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData);
model = chain.Fit(split.TrainSet);
IDataView predictions = model.Transform(split.TestSet);
...
我们玩个游戏好吗?玩西蒙游戏怎么样?
private static ReadOnlySpan<Button> s_allButtons = new[]
{
Button.Red,
Button.Green,
Button.Blue,
Button.Yellow,
};
...
Button[] thisRound = Random.Shared.GetItems(s_allButtons, 31);
// rest of game goes here ...
System.Numerics 和 System.Runtime.Intrinsics
在可能的情况下,我们将 Vector256<T> 重新实现为内部 2x Vector128<T> ops:dotnet/runtime#76221。这能使一些函数部分加速,例如在 Arm64 上 Vector128.IsHardwareAccelerated == true 但 Vector256.IsHardwareAccelerated == false。
我们添加了 Vector512<T> 初始托管实现:dotnet/runtime#76642。与之前的工作项非常相似,这在内部实现为 2x Vector256<T> ops(因此间接实现为 4x Vector128 ops)。这能使一些函数部分加速,即使 Vector512.IsHardwareAccelerated == false 注意:Vector512 还没有直接加速,即使底层硬件支持它也是如此。此类功能应在未来的预览版中启用。
重写 Matrix3x2 和 Matrix4x4 以更好地利用硬件加速:dotnet/runtime#80091。这能使某些基准测试的性能提升高达 48 倍。6-10倍的改进更为常见。
注意:预览版2会对 Quaternion 和 Plane 进行改进。
Hardware Intrinsics 现在用 ConstExpected 属性进行注释:dotnet/runtime#80192。这能确保用户知道底层硬件何时需要常量,因此非常量值何时可能会意外损害性能。
将 Lerp API 添加到 IFloatingPointIeee754<TSelf> 从而添加到 float (System.Single), double (System.Double)和 System.Half和: dotnet/runtime#81186。这能有效且正确地执行两个值之间的线性插值。
JSON 改进
我们不断改进 System.Text.Json,专注于增强源代码生成器在 NativeAOT 应用程序中与 ASP.NET Core 一起使用时的性能和可靠性。下表显示了预览版 1 附带的新功能:
- 缺少成员处理 dotnet/runtime#79945
现在可以配置对象反序列化行为,底层 JSON 负载包含无法映射到反序列化 POCO 类型成员的属性时都可以适用。这可以通过设置一个 JsonUnmappedMemberHandling 值来控制,也可以作为 POCO 类型本身的注释,全局上 JsonSerializerOptions 或通过自定义 JsonTypeInfo 相关类型的合同以编程方式进行控制:
JsonSerializer.Deserialize<MyPoco>("""{"Id" : 42, "AnotherId" : -1 }""");
// JsonException : The JSON property 'AnotherId' could not be mapped to any .NET member contained in type 'MyPoco'.
[JsonUnmappedMemberHandling(JsonUnmappedMemberHandling.Disallow)]
public class MyPoco
{
public int Id { get; set; }
}
- 源生成器支持 required 和 init 属性 dotnet/runtime#79828
源生成器现在支持序列化具有 required 和 init 属性的类型,正如当前在基于反射的序列化中所支持的那样。 - 接口层次结构支持 dotnet/runtime#78788
System.Text.Json 现在支持从接口层次结构序列化属性:
IDerived value = new Derived { Base = 0, Derived =1 };
JsonSerializer.Serialize(value); // {"Base":0,"Derived":1}
public interface IBase
{
public int Base { get; set; }
}
public interface IDerived : IBase
{
public int Derived { get; set; }
}
public class Derived : IDerived
{
public int Base { get; set; }
public int Derived { get; set; }
}
- Snake Case 和 Kebab Case dotnet/runtime#69613
该库现在附带了 snake_case 的命名策略和 kebab-case 属性名称转换。它们的用法与现有的 camelCase 命名策略类似:
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" }
现在可以使用以下命名策略:
namespace System.Text.Json;
public class JsonNamingPolicy
{
public static JsonNamingPolicy CamelCase { get; }
public static JsonNamingPolicy KebabCaseLower { get; }
public static JsonNamingPolicy KebabCaseUpper { get; }
public static JsonNamingPolicy SnakeCaseLower { get; }
public static JsonNamingPolicy SnakeCaseUpper { get; }
}
感谢 @YohDeadfall 贡献了实施。
- 添加 JsonSerializer.MakeReadOnly() 和 IsReadOnly API dotnet/runtime#74431JsonSerializerOptions 类一直使用可冻结语义,但直到现在冻结只能通过将实例传递给其中一种 JsonSerializer 方法来隐式完成。添加新 API 后,用户可以明确控制何时 JsonSerializerOptions 应冻结其实例:
public class MySerializer
{
private JsonSerializerOptions Options { get; }
public MySerializer()
{
Options = new JsonSerializerOptions(JsonSerializerDefaults.Web) { Converters = { new MyCustomConverter() } };
Options.MakeReadOnly(); // Make read-only before exposing the property.
}
}
核心库中以性能为中心的全新类型
多个新类型已添加到核心库中,开发人员能够利用新类型在常见场景中提高代码的性能。
新的命名空间 System.Collections.Frozen 提供 FrozenDictionary<TKey, TValue> 和FrozenSet<T> 集合。这些类型提供了一个不可变的表面区域,一旦创建,键或值就不可以进行任何更改。这反过来又使集合能够根据提供的数据更好地优化后续读取操作(例如 TryGetValue),从而使其能够在构造期有更多时间来优化所有未来的访问。这对于第一次使用时填充、且需在长期服务期间持续存在的集合特别有用,例如:
private static readonly FrozenDictionary<string, bool> s_configurationData =
LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true);
...
if (s_configurationData.TryGetValue(key, out bool setting) && setting)
{
Process();
}
现有类型 ImmutableArray<T>.Builder 还获得了一种将其内容高效转换为 ImmutableArray<T> 的新方法。.NET 8 引入了DrainToImmutable(),它将当前内容作为不可变数组返回,并将构建器的集合重置为零长度数组,它会选择最有效的方法来执行此操作。基于元素的计数,我们可以使用此方法代替有条件地调用 ToImmutable()或 MoveToImmutable()。
新类型的另一个例子是 IndexOfAnyValues<T>,它能帮助开发人员预先投入一些时间以换取以后更快的执行速度。除了像 IndexOfAnyInRange 之类的新方法之外,还添加了接受 IndexOfAnyValues<T> 实例的新重载 IndexOfAny ,可以创建实例来表示要搜索的一组 T 值。此实例的创建处理派生任何必要的数据以优化后续搜索。例如,如果您经常搜索所有 ASCII 字母和数字以及一些标点符号字符,您之前可能会这样写:
private static readonly char[] s_chars = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".ToCharArray();
...
int i = str.IndexOfAny(s_chars);
然而,这要求没有任何类型的向量化能够提高搜索效率,要么需要在每次调用 IndexOfAny 时花时间计算必要的状态以加速操作。现在,您可以这样写:
private static readonly IndexOfAnyValues<char> s_chars = IndexOfAnyValues.Create("-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz");
...
int i = str.AsSpan().IndexOfAny(s_chars);
预先计算所有该状态一次,以便在每次后续调用时都可以重用 IndexOfAny。
新类型 CompositeFormat 会自己反复这种模式。.NET 长期以来一直支持通过 API 进行字符串格式化,例如 string.Format 和 StringBuilder.AppendFormat,例如:
static string GetMessage(int min, int max) =>
string.Format(CultureInfo.InvariantCulture, "Range from {0} to {1}", min, max);
C# 6 添加了对字符串插值的支持,然后 C# 10 结合 .NET 6 显著提高了这些操作的效率,使得相同的操作可以写成:
static string GetMessage(int min, int max) =>
string.Create(CultureInfo.InvariantCulture, $"Range from {min} to {max}");
但是它是在编译时而不是在每次调用 string.Format 时执行可以预先计算的工作。 而这需要在编译时就能获取到格式字符串,以便可以在编译时对其进行解析……如果它直到运行时才获取到怎么办,例如,如果它是从资源文件或其他动态方式加载的?为此,.NET 8 添加了 CompositeFormat 类型。与 IndexOfAnyValues<T> 一样,它可以执行每次使用时需要执行的操作,然后将其取出执行一次。
private static readonly CompositeFormat s_rangeMessage = CompositeFormat.Parse(LoadRangeMessageResource());
...
static string GetMessage(int min, int max) =>
string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max);
这些新的重载还支持泛型参数,以避免装箱开销(boxing overheads)将所有内容都识别为 object。
.NET 8 预览版 1 还增加了对新的以性能为中心的哈希算法的支持,包括新的 XxHash3 和 XxHash128 类型,它们提供了快速 XXH3 和 XXH128 哈希算法的实现。
.NET SDK
dotnet publish 与 dotnet pack 默认生产 Release 资产
Publish(发布)和 Pack(打包)动词的目的是产生生产资产,这意味着它们应该生产Release 资产。在 .NET 8 中,他们将默认执行此操作。
此功能由 PublishRelease 和 PackRelease 布尔属性控制。默认为 true。
用 dotnet publish 演示该功能最简单:
/app# dotnet new console
/app# dotnet build
app -> /app/bin/Debug/net8.0/app.dll
/app# dotnet publish
app -> /app/bin/Release/net8.0/app.dll
app -> /app/bin/Release/net8.0/publish/
/app# dotnet publish -p:PublishRelease=false
app -> /app/bin/Debug/net8.0/app.dll
app -> /app/bin/Debug/net8.0/publish/
请注意,PublishRelease 并且 PackRelease 也存在于从 7.0.200 SDK 开始的 .NET 7 中。它们在 .NET 7 中是可选的,并且必须设置 true 才能执行相同的行为。
请参阅重大更改相关文档:
- dotnet publish
- dotnet pack
Linux 支持
从 dotnet/dotnet 构建您自己的 .NET
.NET 现在可以直接从 dotnet/dotnet 存储库在 Linux 上构建。它使用 dotnet/source-build 构建 .NET 运行时、工具和 SDK。例如,这与 Red Hat 和 Canonical 用于构建 .NET 的构建相同。随着时间的推移,我们将扩展其功能以支持 macOS 和 Windows。
请参阅构建说明以在您自己的计算机上构建 VMR。对于许多人来说,在容器中构建是最简单的方法,因为我们的 dotnet-buildtools/prereqs 容器镜像包含所有必需的依赖项。
我们称这个新存储库为 Virtual Mono Repository (VMR)。它具有真正的 monorepo 的优势,这多亏了开发者们每天在众多现有存储库中(更有效地)所做的定期更新。我们相信,VMR 和更小的“工作存储库”之间的分离是 .NET 项目的未来。我们希望在 VMR 中更容易构建横切功能,但是,我们目前还没有实现。
从源代码构建 .NET 并将其构建成一个完整产品是可行的,我们认为这个新方法就是我们向其迈出的重要一步。
在 .NET 8 之前,从源构建是可行的,但需要从与发布版本相对应的 dotnet/installer commit 提交创建 “source tarball” 。您不再需要进行这一操作。存储库将有与每个发布版本对应的标签,以及持续跟踪产品状态的 main 和 release/8.0-previewN 分支。
.NET 8 + Ubuntu Chiseled容器镜像
我们正在发布安装了 .NET 8 的 Ubuntu Chiseled 镜像. 相比常规容器,这种类型的镜像适用于希望使用有设备式计算优势的开发人员。我们预计,当 .NET 8上线时,Canonical 和 Microsoft 都将支持 Ubuntu chiseled 镜像。
我们计划从 .NET 8 开始,发布以 Ubuntu Chiseled 形式的 dotnet/monitor 镜像。值得一提的是,monitor 镜像是我们发布的生产应用镜像。
Chiseled images 有多种优势:
- 超小图像(减小尺寸和攻击面)
- 没有包管理器(避免整类攻击)
- 没有shell外壳(避免整类攻击)
- 没有 root(避免整类攻击)
您可以由此 aspnetapp sample 查看生产中的的 Chiseled 容器镜像。使用时,您只需要更改一行代码。
.NET 6 和 .NET 7 版本的 Chiseled 镜像现在已被发布到 nightly 存储库中。
Linux 支持和基线目标
我们正在更新支持 .NET 8 的 Linux 系统的最低基线。有三个变化需要注意。
- .NET 产品将针对 Ubuntu 16.04 版本进行构建,适用于所有体系结构。这对于定义 .NET 8 所需最低的 glibc 版本非常重要。例如,由于此项更改,.NET 8 将甚至无法在 Ubuntu 14.04 上启动。
- 对于 Red Hat Enterprise Linux(RHEL),我们将支持 RHEL 8+,启用 RHEL 7。
- 我们只会发布 RHEL 的支持声明,但是,我们希望也能支持其他 RHEL ecosystem distros 生态系统发行版。
重大变化主要就这些。我们仍将支持在 Arm32、Arm64 和 x64 架构上基础上使用 Linux。
请注意,这些更改仅适用于 Microsoft 内部版本。使用 source-build 构建的不同组织可能情况不同,通常为了一个构建生成构建版本仅适用于一个发行版版本,例如 Ubuntu 24.04。
下面演示了 Ubuntu 16.04 glibc 版本以及其用于其他发行版的模式。
$ docker run --rm ubuntu:16.04 ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
代码的生成
社区 PRs (非常感谢 JIT 论坛的 contributors!)
- @am11 更新了 CLRConfiguration 和 jithost 中的 env 变量 PR#77025。
- @En3Tho 将 (X & 1) != 0 优化为 (X & 1) 和 (X & 1) == 0 以及 ((NOT X) & 1) in PR#74806, 并修复了与 faulty LIR range 相关的漏 PR#77166。
- @MichalPetryka 实现了Type.IsEnum 和 Type.GetEnumUnderlyingType 在 PR#71685的内部函数, 并将MemoryMarshal.GetArrayDataReference 转换为 JIT 内部函数 PR#79760。
- @pedrobsaila 在 PR#62689 中做出了第一个 PR 贡献,发出无分支表单从 (x >= 0 && y >= 0) 到 (x | y) >= 0 ,从 (x != 0 && y != 0) 到 (x | y) != 0。
- @a74nh, @AndyJGraham and @swapnilGaikwad 对 Arm64 性能改进做出了贡献(请参阅 Arm64 部分)。
- @DeepakRajendrakumaran 为 AVX-512 做出了贡献(见AVX-512部分)。
- @SingleAccretion 为预览版本1进行了72个拉取请求 72 PR contributions 其中有:
1.PR#72719 优化的内存加载/在强制转换下存储
2.PR#77238 和 PR#76139 是与 SSA 相关的改进
3.PR#78246 通过删除 ADDR 节点简化 JIT IR
4.PR#77990 优化固定存储
云原生
- PR#79709 删除了非 GC 静态字段的帮助程序调用, PR#80969 优化了 GC 类型的静态字段。
- PR#80831 对单态案例实现将强制转换到接口进行非虚拟化。
Arm64
Arm64 性能改进工作正在按计划进行 Issue#77010。
- @AndyJGraham and @a74nh 实施了与 ldp 和 stp 相关的窥视孔优化 PR#77540
- @a74nh 在PR#73472, PR#77728, PR#78223, 和 PR#77888 中启用‘If Conversion’
- @swapnilGaikwad 在条件选择中使用零寄存器(csel) PR#78330
- @SwapnilGaikwad 在 PR#79550启用 mneg ,多选择中的一项 (Issue#68028)
- 通过比较PR#75864 和 PR#75999得出更快的矢量
- PR#75823 添加了对 Arm64 上的“移位寄存器”操作的支持
AVX-512
- .NET 8 将按计划支持 AVX-512 ISA 扩展 Issue#77034.
- PR#76642 实现了 API, 公开Issue#73262中Vector512<T> 类型
- 虚拟机中添加 AVX-512 状态已通过 @DeepakRajendrakumaran 的同意收到支持 PR#74113
- @DeepakRajendrakumaran 添加了对emitOutput 输出 路径的EVEX 编码支持PR#75934, PR#77419 和 PR#78044
- JitInterface 已由@DeepakRajendrakumaran 更新为Vector512 PR#81197
一般SIMD改进
- PR#77562 为在 Issue#76593 定义的 Vector64/128/256/512<T> 和 Vector<T>上新批准的 API 实施了额外的内部函数
- PR#79720 使用 HWIntrinsics 实现 Vector2/3/4 和 Vector<T>
- PR#77947 为 OrdinalIgnoreCase 矢量化 String.Equals
PGO
PGO 的基本改进正在按计划进行中 Issue#74873。
- 引入了新的 JIT 层,以仅检测热 Tier0 和 R2R 代码。这意味着您不再需要禁用 ReadyToRun 并牺牲启动时间来获得完全 PGO 级别的性能优势: PR#70941
- PR#80481 为所有场景启用了基于边缘的配置文件
- 构建预测列表已移至 JIT 的早期阶段:
PR#80625, PR#80856, PR#81288, PR#81246, PR#81196, PR#81000, 和 PR#80891。
循环优化
- PR#75140 在循环克隆中支持委托 GDV guards
- PR#80353 扩展循环展开优化
一般优化
@SingleAccretion 在PR#76263 Long中启用了32 位解锁字段注册上的多注册变量提升。
- PR#77103 实施了 Issue#8795中提出的新尾部合并优化
- PR#81055 确保 Span<T>.Length 和 ROSpan<T>.Length 被识别为“never negative”
- PR#79346 添加了一个早期的活跃度传递,允许 JIT 在传递结构参数时删除大量不必要的结构副本
- PR#77874 删除了一些涉及小整数类型的简单操作的不必要的零/符号扩展指令
- 字符串文字、typeof()、静态字段通过 PR#49576, PR#75573和 PR#76112
1.允许 JIT 在某些情况下省略 GC 写障碍 PR#76135
2.typeof(..) 在大多数情况下不再需要助手调用,例如:
Type GetMyType() => typeof(string);
; Method MyType():System.Type:this
3.4883EC28 sub rsp, 40
4.48B918083857FC7F0000 mov rcx, 0x7FFC57380818
5.E80DE8AB5F call CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
6.90 nop
7.4883C428 add rsp, 40
8.48B8B800000364020000 mov rax, 0x264030000B8 ; ‘System.String’ C3 ret -; Total bytes of code: 25 +; Total bytes of code: 11
- 静态和静态只读字段的一批改
进 PR#77102, PR#77593, PR#77354, PR#77737, PR#78593, PR#78736 and PR#78783
- PR#81005 中显示的表达式就是一个很好的例子。JIT 现在能够在.NET 8 中折叠使用
JIT 吞吐量改进
- PR#80265 将 JitHashTable 迭代转换为基于范围的迭代for,将吞吐量提高了 0.22%
总之,.NET 8 预览版1的发布是 Microsoft 多元化工程师团队与高度参与的开源社区之间良好协作的证明。.NET 8 中的新功能和改进是社区成员辛勤努力和奉献的成果,我们非常感谢大家做出的贡献。
该社区重视包容性和多样性,能成为其中的一员,我们很自豪。我们致力于建立一个人人都可以访问的技术生态系统。我们相信,只要我们一起努力,就可以取得伟大的胜利,我们对 .NET 的未来充满期待。
点我阅读原博客,获取更多详细内容和相关链接~