官宣 .NET 8 Preview 1的发布

Songjie Cai

本文翻译于Jeremy Likness的这篇英文文章:Announcing .NET 8 Preview 1 – .NET Blog (microsoft.com).

欢迎使用 .NET 8! 第一个预览版可供您下载: claim your copy of the first .NET 8 preview 并立即开始构建应用程序。向下滚动以查看此预览中包含的功能列表。.NET 8 是一个长期支持 (LTS) 版本。这篇博文涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8预览版和发布候选版本将每月交付一次。 像往常一样,最终版本将在 11 月的某个时候在 .NET Conf 上发布。

Image Picture1

.NET 版本包括产品、库、运行时和工具,代表Microsoft 内外多个团队之间的协作。 这篇博文中涵盖的更广泛的主题并不包含.NET 8的所有关键场景和投资。它们代表了很大的领域,但只是进入.NET 8 的所有重要工作的一部分。我们计划对ASP.NET Core, Blazor, EF Core, WinForms, WPF和其他平台进行广泛的投资。您可以通过阅读产品路线图了解有关这些领域的更多信息:

请务必查看themesof.net 了解有关GitHub问题跟踪 .NET 8里程碑的更多详细信息。

您可以下载适用于 Windows, macOS, and Linux  的 .NET  8 preview 1

通过阅读.NET 8 文档中的新增功能来了解最新的和即将到来的新功能,该文档将在整个版本中更新。当我们的团队发布新的预览版时,我们将在其中包含已知功能的摘要。

.NET 8 已通过 17.6 Preview 1测试。如果你想尝试 .NET 8 和 Visual Studio 系列产品,我们建议你使用preview channel builds。Visual Studio for Mac 对 .NET 8 预览版的支持尚不可用,但即将推出。

欢迎使用 .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 应用程序的性能产生重大影响。感谢AdeelFilip将 NativeAOT 功能引入 macOS 进行预览 1。.NET 团队将专注于完善 .NET 8 的一些基础知识,例如大小(请参阅dotnet/runtime#79003)。使用NativeAOT发布应用程序会创建一个完全独立的应用程序版本,不需要单独的运行时,因为所有内容都包含在单个文件中。从预览版 1 开始,这个文件变小了。事实上,Linux 版本现在最多缩小了 50%。

以下是包含整个 .NET 运行时的Native AOT的“Hello, World”应用程序的大小:

.NET 7 .NET 8 Preview 1
Linux x64 (with -p:StripSymbols=true) 3.76 MB 1.84 MB
Windows x64 2.85 MB 1.77 MB

 

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。这种方法的目标是更清楚地描述预览版。这是根据社区请求进行的更改。

与非nonroot)用户一起运行容器镜像:尽管容器基础镜像几乎总是配置为与根用户一起运行——这种设置往往会保留在生产环境中——但它并不总是最好的方法。然而,将每个应用程序配置为拥有不同的用户是一件很痛苦的事情,而且容器镜像不会附带适合容器工作负载的非根用户。

.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 附带的新功能:

现在可以配置对象反序列化行为,底层 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 属性的类型,正如当前在基于反射的序列化中所支持的那样。

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属性名称转换。它们的用法与现有的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贡献了实施。

JsonSerializerOptions类一直使用可冻结语义,但直到现在冻结只能通过将实例传递给其中一种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才能执行相同的行为。

请参阅重大更改相关文档:

Linux 支持

从 dotnet/dotnet 构建您自己的 .NET

.NET 现在可以直接从dotnet/dotnet存储库在 Linux 上构建。它使用dotnet/source-build构建 .NET 运行时、工具和 SDK。例如,这与Red HatCanonical用于构建 .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 实现了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 其中有:
  • PR#72719 优化的内存加载/在强制转换下存储
  • PR#77238 和 PR#76139 是与 SSA 相关的改进
  • PR#78246 通过删除 ADDR 节点简化 JIT IR
  • 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矢量化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.
  • 允许 JIT 在某些情况下省略 GC 写障碍 PR#76135.
  • typeof(..) 在大多数情况下不再需要助手调用,例如:
Type GetMyType() => typeof(string);
; Method MyType():System.Type:this
  • 4883EC28 sub rsp, 40
  • 48B918083857FC7F0000 mov rcx, 0x7FFC57380818
  • E80DE8AB5F call CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
  • 90 nop
  • 4883C428 add rsp, 40
  • 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,将吞吐量提高了22%。

社区聚焦(Youssef Victor)

如果没有 .NET 社区成员贡献的大量周全的建议和意见,.NET 就无法被如此广泛的推广。特别感谢这篇文章的作者——社区之星成员 @Youssef Victor, 他分享了作为微软 MVP 的经历。

Image dotnet 8 preview 1 community spotlight

Youssef’s 自述:

“我叫Youssef Victor,是亚历山大大学计算机与通信系的本科生。我从 2019 年开始为 .NET 组织(具体来说,是 dotnet/docs 和 dotnet/samples 存储库)贡献自己的力量。

说起来事发偶然,当时我发现一些与 .NET 编码指南违背的示例,并在 docs.microsoft.com(现在是learn.microsoft.com)中找到了小编辑按钮。我决定分叉存储库并进行一些更改。该团队与像我一样的贡献者沟通良好,他们合并 PR 的速度也很迅速!在那之后我一直为此努力,试尽我所能帮助改进文档。

后来,我研究了所用产品的代码,发现dotnet/roslyn和dotnet/roslyn-analyzers这两个存储库很有趣。相应的团队也和文档团队一样乐于助人。在我的参与的过程中,他们提供了很多帮助。对于 dotnet/roslyn-analyzers 存储库,我帮助团队根据现有问题编写新的分析器,进行代码修复,针对为新的分析器提出的建议建立新问题,修复漏洞,审查代码,最近还一起对问题进行分类。我通过编译器对dotnet/roslyn repo提供帮助,包括参与了一个名为CallerArgumentExpression的C# 10语言功能开发。还修复了一些漏洞。

其余时间我都通过IDE进行操作,包括IntelliSense问题,突出显示问题,为新语言功能实现生产力功能等。这是一次之前我根本没想过的经历。除此之外,我的贡献得到了认可,我被提名并被选为微软MVP!“

结语

总之,.NET 8 预览版 1的发布是 Microsoft 多元化工程师团队与高度参与的开源社区之间良好协作的证明。.NET 8 中的新功能和改进是社区成员辛勤努力和奉献的成果,我们非常感谢大家做出的贡献。

该社区重视包容性和多样性,能成为其中的一员,我们很自豪。我们致力于建立一个人人都可以访问的技术生态系统。我们相信,只要我们一起努力,就可以取得伟大的胜利,我们对.NET 的未来充满期待。

我们要向已经为 .NET 8 做过贡献的每个人表示衷心的感谢,我们将感谢写在这里sincere thanks to everyone who has contributed to .NET 8 so far, 无论您是帮助我们修改过代码、报告过错误还是提供过反馈,您所做出的的贡献都使得.NET 8 预览版 1最后得以上线。我们期待,在大家坚持不懈的努力下,.NET 和整个技术社区能拥有更光明的未来。

 

1 comment

Leave a comment

  • 德枫 洪 0

    谢谢您的翻译

Feedback usabilla icon