宣布.NET 5(预览版4)和我们的.NET之旅

2020-05-20 04:44:30

.NET 5是.NET的下一个版本和未来。我们正在继续统一.NET平台的旅程,用一个单一的框架从云扩展到桌面,再扩展到移动设备,甚至更远的地方。回过头来看,我们充分利用了.NET Framework的优点,并将其放入.NET Core3中,包括对WPF和Windows窗体的支持。随着旅程的继续,我们将移动Xamarin和.NET Web程序集以使用.NET5库,并扩展DotNet工具以在浏览器中定位移动和Web程序集。同时,我们将继续改进.NET作为领先的云和容器运行时的功能。

您可以收听Scott Hanselman和我在今天的“.NET之旅”演讲中谈论.NET5及以后的内容。

我们想听到你的消息!在https://aka.ms/dotnet5_feedback_blog.上分享您对.NET 5的反馈。我们非常重视您的反馈,并将其用于帮助制定.NET的未来决策。

去年,我们制定了一个.NET和.NET5的愿景,我们说我们将采用.NET Core和Mono/Xamarin实现,并将它们统一到一个基类库(BCL)和工具链(SDK)中。在全球卫生大流行之后,我们必须适应客户不断变化的需求,并提供必要的支持,以帮助他们顺利运营。我们的努力继续立足于帮助我们的客户解决他们最迫切的需求。因此,我们预计这些功能将在2020年11月发布预览版,但统一将在我们的长期支持(LTS)版本.NET6中真正完成。我们的愿景没有改变,但是我们的时间表改变了。

我们仍然致力于一个.NET平台,并将在今年11月发布一个高质量的.NET5版本。在通往一个.NET的旅程中,您将继续看到随着多个预览版的出现而出现的创新浪潮。

ASP.NET Core和EF Core也将于今天发布。PowerShell今天发布了一个基于.NET5的版本(POST将在今天晚些时候发布),现在正在按.NET计划发布。

您需要Visual Studio 2019 16.6或更高版本才能使用.NET 5.0。要将.NET 5.0与Visual Studio代码配合使用,请安装最新版本的C#扩展。Visual Studio for Mac尚不支持.NET 5.0。

让我们来看看我们预计在11月份与.NET5一起发布的一些亮点。预览版4中包含了这些更改中的许多部分或全部。这些亮点将更清晰地描述当您采用.NET 5时,您将在开发过程和生产中获得的改进。

一致的性能:我们更加关注可预测的一致性能,减少性能悬崖和异常值,重点放在P95+延迟上。改进分层JIT编译使用的调用计数机制,以平滑启动期间的性能。

单文件应用程序-一种新的单文件发布类型,它从单个二进制文件中执行您的应用程序(例如,可以在只读介质上使用)。

Windows ARM64-使.NET能够在Windows ARM64上本地运行,支持在客户计算机上开发和部署客户端应用程序。

容器-减小容器映像大小并实现新的容器API,以使.NET能够保持最新的容器运行时演变。

我将分享一些关于这些改进的更详细的信息,以及我们看到它们的发展方向。

我们正在使用.NET5.0更改用于目标框架的方法。以下两个项目文件示例通过指定各自的目标框架名字对象(TFM)来演示如何使用.NET Core3.1和.NET5.0目标框架。您可以看到一个新的、更紧凑的.NET5.0 TFM:

我们正在对.NET5.0的.NETtfms进行几个重要的更改,以简化它们的使用,减少概念,并使其更容易公开特定于操作系统的API。

随着.NET的发展,以API版本为目标将变得更加简单。我们不会有两个TFM系列,比如:netcoreapp3.1和netStandard2.0。相反,我们只有一个,比如:net5.0和net6.0。这是因为未来只有一个.NET实现,因此不再需要.NET标准(它使多个.NET产品的库兼容)。您还可以瞄准操作系统API,对TFM做一个小小的扩展,比如net5.0-windows和net6.0-android。我们还将从新的项目文件中删除不同的SDK,例如Sdk=";Microsoft.NET.Sdk.WindowsDesktop";,因为Net5.0-WINDOWS将提供相同的信息。最大的好处是,通过以net5.0为目标,您可以100%访问跨平台API,而不是碰巧在.NET标准中的子集。使用哪种TFM总是显而易见的(它要么是可移植的代码,要么是特定于操作系统的),而且您永远不需要等待Span<;T>;这样的API出现。

.NET 6.0将使用与net6.0相同的方法,并将添加net6.0-iOS和net6.0-android。

这些变化是因为我们认为.NET Core是.NET的未来,我们已经从产品的各个方面去掉了“Core”这个名字,包括API和容器Repos。我们也看到了进一步简化.NET的机会,在.NET 5.0+中去掉了.NET标准这一概念。.NET标准通过与.NET Framework和Xamarin建立桥梁,在建立.NET核心方面发挥了关键作用。NET Standard 2.0版本将保持多年的相关性,如果您需要支持.NET Framework,我们建议您使用它。对于不需要在.NET Framework上运行的应用程序和库,我们建议以net5.0 TFM为目标,这将使您能够访问最大的跨平台API集。对于Xamarin来说,.NET Standard 2.0和2.1仍然是相关的,但是,一旦Xamarin作为.NET 6.0的一部分集成到.NET中,那么它将切换到net6.0 tfms,并且开发人员将专门针对.NET框架兼容性而将.NET Standard 2.0作为目标。

你可能有更多的问题需要回答。在发布.NET5.0之前,我们将发布一篇关于这个主题的更大的博客文章。以下几点回答了剩下的一些最明显的问题:

我们不希望创建任何新的网络标准版本。.NET Standard 2.1很可能是最后一个版本。

现在还没有net5.0-Linux TFM的计划,因为我们(目前)还没有公开任何特定于Linux的API。此外,“Linux”不是单一的统一数量,因此不清楚哪些API会在这样的TFM中公开。我们可以公开POSIX标准,但是我们将其命名为net5.0-POSIX,并且它可以在除Linux之外的其他操作系统上工作。不过,我们也没有这方面的计划。

我们不打算为Web程序集公开TFM,原因与Linux中描述的类似。

不能将.NET Framework项目中的TargetFrameworkVersion更新为5.0并期望它成为.NET 5.0项目。这是行不通的。相反,您需要将应用程序移植到.NET Core。对于库,您可以移植到.NET Standard或.NET Core。我们不再向.NET Core添加.NET Framework API,因此无需等待将您的应用程序移植到.NET Core。

新的TFM计划是工作负载项目的基础部分。我们将在.NET5.0中添加对工作负载的最小支持,然后在.NET6.0中实现完整的愿景。

.NET 5包括C#9。C#9将有许多特性,包括记录、顶级语句、改进的模式匹配等等。下面是第一个预览版中的一些模式匹配改进:

今天,我们很高兴地宣布,Windows Forms Designer for.NET Core Projects现在可以作为Visual Studio 2019版本16.6的预览版!Visual Studio16.7预览版1中还提供了较新版本的设计器!

要在Visual Studio中启用设计器,请转到工具&>选项&>环境&>预览功能,然后选择使用.NET核心应用程序的Windows窗体设计器预览选项。

新的设计器支持所有Windows窗体控件,除了DataGridView和ToolStripContainer(即将推出)。它包括您预期的所有其他设计器功能,包括:拖放、选择、移动和调整大小、控件的剪切/复制/粘贴/删除、与“属性”窗口的集成、事件生成等。数据绑定和对第三方控件的支持很快就会到来。

.NET应用程序现在可以在Windows ARM64上本地运行。在此之前,我们在.NET Core 3.0中添加了对Linux ARM64的支持。使用.NET 5.0,您可以在Windows ARM64设备上开发Web和UI应用程序,并将您的应用程序交付给拥有Surface Pro X和类似设备的用户。您已经可以在Windows ARM64上运行.NET Core和.NET Framework应用程序,但要通过x86仿真。这是可行的,但是本机ARM64执行的性能要好得多。

您可以在ARM64上下载并使用.NET5.0SDK和今天的预览版4。目前,仅支持控制台和ASP.NET核心应用程序。请参阅.NET 5.0 ARM64跟踪问题以跟踪进度。

主分支添加对Windows窗体的支持。这一变化可能会进入预览版5,但预览版6肯定会出现。您可以从DotNet/Installer下载主分支构建。

目前需要下载并解压ARM64的.zip文件。我们打算在.NET5最终版本中添加ARM64MSI。

我们一直与PowerShell团队密切合作,在Windows ARM64上验证并启用PowerShell 7.1。该团队推出Windows ARM64“试验性”版本已经有一段时间了,并打算在Windows ARM64上支持PowerShell7.1。Powershell7.1是基于.NET5.0构建的,应该大约在同一时间发布。

下图演示了在Windows ARM64上运行的Conway‘s Game of Life VB和Windows窗体示例。

一年多来,我们在改进ARM64性能方面投入了大量资金。我们致力于使ARM64成为具有.NET的高性能平台。平台的可移植性和一致性一直是.NET的显著特点。这包括无论您在哪里使用.NET,都能提供出色的性能。在.NET Core 3.x中,ARM64的功能与x64相当,但缺少一些关键的性能特性和投资。我们在.NET5.0中对ARM64性能进行了第一次重大投资。

硬件特性是我们在.NET Core3.0中添加的低级性能特性。当时,我们增加了对x64指令和芯片的支持。作为.NET 5.0的一部分,我们正在扩展该功能以支持ARM64。仅仅创建内部函数并不能提高性能。您需要在性能关键型代码中使用它们。我们在.NET5.0的.NET库中广泛利用了ARM64的内部特性。您也可以在自己的代码中做到这一点,尽管您需要熟悉CPU指令才能做到这一点。

我将用一个类比来解释硬件内部是如何工作的。在很大程度上,开发人员依赖于.NET中内置的类型和API,如String.Split或HttpClient。这些API通常通过P/Invoke功能利用本机操作系统API。P/Invoke支持高性能的本机互操作,并在BCL中为此广泛使用。您可以自己使用相同的功能来调用本机API。硬件内部功能类似,不同之处在于它们不是调用操作系统API,而是使您能够在代码中直接使用CPU指令。它大致相当于.NET版本的C++内部函数。硬件本质最好被认为是CPU硬件加速功能。它们提供了非常实实在在的好处,现在是.NET库性能基础的关键部分,并为您在我们的性能博客文章中读到的许多好处负责。与C++相比,当.NET内部函数被AOT编译成随时可以运行的文件时,内部函数没有运行时性能损失。

注意:Visual C++编译器具有类似的内部功能。您可以直接将C++与.NET硬件内部功能进行比较,如果您在System.Runtime.Intrinsics.X86.Avx2、x64(AMD64)内部功能列表和英特尔内部功能指南中搜索_mm_i32ather_ep32,就可以看到这一点。你会看到很多相似之处。

我们在5.0中对ARM64性能进行了第一次重大投资,但将在后续版本中继续这一努力。我们直接与ARM控股的工程师合作,确定产品改进的优先顺序,并设计最充分利用ARMv8 ISA的算法。其中一些改进将增加ARM32的价值,然而,我们并没有将独特的努力应用于ARM32。

请与我们分享任何与ARM64相关的性能信息,无论是3.1到5.0的显著改进,还是5.0的性能应该会更好。

我们看到越来越多的大型面向互联网的网站和服务托管在.NET上,虽然有很多合理的关注点放在每秒请求数(RPS)指标上,但我们发现很少有大的网站所有者问我们这个问题,或者要求数百万的RPS。然而,我们听说了很多关于延迟的事情,特别是关于改善P95或P99延迟的问题。通常,为站点配置的机器或核心的数量(以及最大的成本驱动因素)是基于达到特定的P95指标(而不是P50)来选择的。我们认为延迟是真正的“金钱指标”。

我们在StackOverflow的朋友们在分享他们服务上的数据方面做得很好。他们的一位工程师尼克·克雷弗(Nick Craver)最近分享了他们在迁移到.NET Core后看到的延迟改进:

问题的中位数页面呈现时间从大约21ms(由于GC的原因,我们最近略有增加)下降到约15ms。

第95个百分位数从~40ms下降到~30ms(相同的测量)。第99位从~60ms下降到~45ms。

虽然您可以看到我们在延迟方面取得了很好的进展,但我们远远不满意。在(遥远的)过去,我们构建了服务器GC和后台GC等功能,通过分别利用多核和线程等当然粒度的CPU功能来改善延迟。然而,这些仍然非常重要,我们需要更具创造性,以显著改善向前发展的延迟,至少在与GC相关的方面是这样。我们已经沿着这些路线启动了多个项目。

固定对象一直是GC性能的长期挑战,特别是因为它们加速(或导致)内存碎片。我们为固定的对象添加了一个新的GC堆。固定对象堆基于这样的假设,即进程中固定的对象非常少,但它们的存在会造成不成比例的性能挑战。将固定的对象(特别是那些由.NET库创建的对象作为实现细节)移动到一个独特的区域是有意义的,从而使世代GC堆只有很少的固定对象,甚至没有固定的对象,因此具有更高的性能。

最近,我们一直在解决GC中长期存在的“难题”。DotNet/Runtime#2795对GC静态扫描应用了一种新方法,该方法在确定GC堆对象的活跃度时避免了锁争用。dotnet/coreclr#25986使用了一种新的算法,用于在垃圾收集的标记阶段跨核心平衡GC工作,这应该会增加具有大型堆的垃圾收集的吞吐量,从而减少延迟。

我们认为容器是最重要的云趋势,并且已经在这一模式上投入了大量资金。我们至少以四种不同的方式在.NET软件堆栈的多个级别投资容器。

一是我们对基本面的投入。声称这些投资的功劳有点奇怪,因为它们也会使非容器工作负载受益。可能并不明显的是,我们收到的影响我们基本面投资的反馈越来越多地来自部署容器化应用程序的开发人员。这些投资偏向集装箱。

我们正在努力让.NET在容器中表现得更好。去年年底,我们听到了有关.NET Core3.1更改(后来被恢复)导致性能不佳的报道。我们现在正在调查在高密度和其他配置中使用.NET的性能,以帮助了解我们预期的一组相对范围内的更改,这些更改将释放容器中下一个重大的性能改进。应该注意的是,.NET Core3.0对于.NET和容器来说是一个非常大的版本,3.1版本只是一个小的(短暂的)问题。

我们一直在寻找机会来改善我们发布的图像。这包括减小图像大小,但也扩展了我们发布的图像集。根据我们从GitHub和其他来源获得的反馈,我们决定开始发布Windows Server Core映像。以下是我们开始发布这些图像时将使用的示例Dockerfile。我们还进行了其他更改,缩小了Windows Server Core映像的大小,使其更易于使用。

最后,我们正在努力使与容器协调器和类似环境的工作变得更容易。我们正在添加对OpenTelemeter的开箱即用支持,这样您就可以从您的应用程序中捕获分布式跟踪和指标。我们还在DotNet/Tye repo中开发一套新的实验工具,旨在提高微服务开发人员的生产力,用于开发和部署到Kubernetes环境。

我们一直致力于改进多版本的分层编译。我们继续将其视为启动和稳定性能的关键性能特性。在这个版本中,我们对分层编译做了两大改进。

分层编译的主要机制是调用计数。一旦一个方法被调用n次,运行库就会要求JIT以更高的质量重新编译该方法。从我们最早的性能分析中,我们知道呼叫计数机制太慢(从长远的角度来看),但没有看到解决这个问题的直接方法。作为.NET5.0的一部分,我们改进了分层JIT编译使用的调用计数机制,以平滑启动期间的性能。在过去的版本中,我们已经看到在进程生命周期的前10-15秒(主要针对Web服务器)的不可预测的性能报告。现在应该解决这个问题了。请测试一下,然后告诉我们你看到了什么。

我们发现的另一个性能挑战是对带循环的方法使用分层编译。基本问题是,您可以使用一个循环迭代一百万次的冷方法(只调用一次或几次;<;n)。这种病态情况的一个很好的例子是应用程序的Program.Main方法。因此,默认情况下,我们禁用了具有循环的方法的分层编译。相反,我们使应用程序能够选择对具有循环的方法使用分层编译。PowerShell是在看到某些场景的高个位数性能改进后选择这样做的应用程序。

为了更好地处理具有循环的方法,我们实现了堆栈上替换(OSR)。这类似于Java虚拟机具有的同名功能。OSR允许由当前运行的方法执行的代码在方法执行过程中重新编译,而这些方法是活动的“堆栈上”。此功能目前处于试验阶段,并可选择加入(在x64上)。

要使用OSR,必须启用多项功能。PowerShell项目文件是一个很好的起点。您会注意到分层编译和所有快速JIT功能都已启用。此外,您需要设置COMPLUS_TC_OnStackReplace=1(它是一个环境变量)。

或者,您也可以设置以下两个环境变量,假设所有其他设置都有其默认值:

我们不打算在.NET5.0中默认启用OSR,也还没有决定是否在生产中支持它。请将您对该功能的所有反馈意见提供给我们。我们现在正在积极测试,稍后会分享更多的见解。

有钥匙%s。

..