深度探秘.NET 5
今年11月10号 .NET 5.0 如约而至。这是.NET All in one后的第一个版本,虽然不是LTS(Long term support)版本,但是是生产环境可用的。 有微软的背书,微软从.NET Preview 1就开始在自己的网站上运行.NET 5,(Bing.com、dot.net已升级并运行了数个月),同时早期的.NET Core版本可以直接升级到.NET 5. 所以大家可以放心使用的。 接下来,我们探秘.NET 5.0这次带来了哪些新的特性。 一、.NET 5.0 的一些亮点(Highlights) 1. 通过线上(生产环境)测试(battle-tested) :?.NET5.0 通过在Bing.com和dot.net 托管运行数个月,全面通过了线上验证,这证明这个版本是生产可用的 2. 性能大幅提升:GC、JIT、正则表达式、多线程和异步处理、集合、LINQ、网络访问、JSON序列化、gRPC等等,了解详细可以访问
3. C# 9和F# 9 的语音提升:例如C#9的顶级程序和记录,而F#5提供了交互式编程,并提高了.NET上的功能性编程的性能。 4.?.NET库增强了Json序列化,正则表达式和HTTP(HTTP 1.1,HTTP / 2)的性能。这一点在第二条中已经有所涉及。 5. P95 的延迟有所减少,得益于GC、分层编译和其他组件的一些改进 6.更好、更灵活的应用部署选项:ClickOnce客户端应用程序发布,单文件应用程序,减小的容器映像大小以及添加的Server Core容器映像。 7.平台支持的范围进一步扩展:Windows Arm64和WebAssembly ?二、再看统一平台的愿景 ? ?2019年5月6号,微软发布了.NET 5.0 统一平台的愿景:将来只会有一个.NET,您将可以使用它来定位Windows,Linux,macOS,iOS,Android,tvOS,watchOS和WebAssembly等。 ? ? ? ?实现这一愿景的第一步是整合.NET仓库,即:整合关键的.NET代码库, 其中包括很大一部分的Mono。为.NET运行库和库提供一个存储库是在各处交付相同产品的前提。Blazor是利用代码合并和.NET统一的最佳示例。Blazor WebAssembly的运行时和库现在是从合并的dotnet /运行时仓库中构建的。这意味着服务器上的Blazor WebAssembly和Blazor使用与完全相同的代码List<T>。 ? ?代码整合后,.NET Framework怎么办? ? ?.NET Framework仍然是受支持的Microsoft产品,并且每个新版本的Windows都将继续支持.NET Framework。去年,微软宣布已停止向.NET Framework添加新功能,并已向.NET Core添加.NET Framework API。 ? ?这就意味着,.NET Framework已经停更了,版面目前停留在.NET Framework 4.8.? ? ?这也是没办法的事情,统一后的.NET,从.NET5.0开始迭代了。这次.NET 5.0的Release列表也能发现这个情况: ? ? ? ? 在上述情况下,目前是将.NET Framework升级到.NET Core的最佳时机了。如果比较在意LTS版本,也可以等到明年.NET 6统一升级。对于此,微软的建议是: ? ??对于.NET Framework客户端开发人员,.NET 5.0支持Windows窗体和WPF。 ? ? 对于.NET Framework服务器开发人员, 如果采用ASP.NET Core才能使用.NET 5.0。 ? ? 对于Web Forms开发人员,Blazor通过高效且更加现代的实现方式提供类似的开发人员体验。 ? ? 对于WCF服务器和Workflow用户可以查看支持这些框架的社区项目。 ? ? 以上,对于统一后的.NET 5.0,广大.NET Developers 可以放心、开心地去拥抱这次升级和统一,这代表了.NET的未来。 ?三、深入看一下编程语言层面的提升(C# 9 和 F# 5) ? ?C#9和F#5是.NET 5.0版本的一部分,被包含在.NET 5.0 SDK中。接下来详细看一下C# 9 的一些语言新特性(F# 5用的比较少,不再做详细介绍): ? 1.?Top-level programs 顶级程序 ? ?大家会问这是什么?这是在顶级编写程序的一种更简单的方式:一个更简单的 Program.cs 文件。 ? ?我们知道,原先在Program类中,必须有Main函数,这是程序的一个EntryPoint入口。 using System; namespace NET5Demo { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } } ? ?.NET 5引入Top-level programs 后,我们不需要写Main函数了。可以直接这么写: System.Console.WriteLine(");
?大家会有疑问,真的没有Main函数了吗?其实这是个语法糖,我们通过IL Spy看一下反编译后的代码: ? ? 2. 逻辑模式和属性模式匹配(Logical and property patterns) ? 我们可以使用not or and 实现更强的更灵活的逻辑模式匹配: ? 先看一个逻辑匹配的Demo: var input = Console.ReadKey(); if (input.KeyChar is 'Y' or y') { Console.WriteLine(You choosed yes!); } ? 再看一个Switch的Demo: int score = 90; switch (score) { case 0: Console.WriteLine(0分.); break; case > 0 and <= 60合格.60 and <= 80优秀.80 and <= 100卓越.; } ?属性模式匹配:通过两个{},实现对对象属性的模式匹配。 Type type = Type.GetType(System.String); if (type is not null and { FullName: }) { Console.WriteLine(It's type is System.String.); } ? 3. record类型 ??record是一个新增的引用类型,与class很像,那么大家会问?为什么增加一个record类型呢?它的使用场景是什么呢? ? 答案:为了方便比较数据是否一致。我们写个代码示意一下: ? 假设我们有个User类,包含ID、Name、Gender、Tel几个属性,如果我们要对比2个User对象是否相等,我们可能需要逐个属性对比,或重写Equals、GetHashCode方法。 ? 那么如果我们用record类型呢? record User(int Id,string Name,int Gender,string Tel); ?做个对象对比的Demo: var userA = new User(1,"小米",1,"123456789"); if (userA == userB) { Console.WriteLine(这是一个用户.); } ?总结一下:record类型让开发省去了重写相等比较的业务逻辑,同时简化了类型定义和初始化。 ?4. 可空注解的提升 ? 目前.NET library 类库,已经全面设置了是否可空注解。其实这个特性其实在C# 8.0已经引入:C#8.0 引入了“可为空引用类型”和“不可为空引用类型”,使你能够对引用类型变量的属性作出重要声明 : ? #nullable enable ? 即.NET 5.0的类库中已经全面更新了这个注解,方便开发时进行查看。 ? 同时,这次引入新的成员是否为空的注解:MemberNotNull 和?MemberNotNullWhen,例如以下的代码: UserManager { User user = new User(1,小米",1)">123456789); [MemberNotNull(nameof(user))] public string GetUserName( id) { return user.Name; } } ? 编译器会智能提示:CS8602警告 ?? ?四、工具类的新变化 ??.NET 5.0 改进了Windows窗体设计器,更改了目标框架适用于.NET 5.0及更高版本的方式,更改了WinRT的支持方式,以及其他的一些改进。 ? 1. Windows窗体设计器:winform设计器 ? ?Windows Forms设计器(用于.NET Core 3.1和.NET 5.0)已经在Visual Studio 16.8中进行了更新,现在支持所有Windows Forms控件。它还支持WinForms控件的Telerik UI。设计器包括您期望的所有设计器功能,包括:拖放,选择,移动和调整大小,剪切/复制/粘贴/删除控件,与属性窗口集成,事件生成等。数据绑定和对更广泛的第三方控件的支持即将推出。 ? ? ? ?2.?.NET 5.0目标框架 ? ?新增一个Console类型工程后,选择目标框架是.NET 5.0,其Project文件内容是这样的: ? ? ? ?新增一个Windows窗体应用工程后,选择目标框架是.NET 5.0,其Project文件内容是这样的: ? ? ? ?Windows桌面API(包括Windows窗体,WPF和WinRT)仅在定位时可用net5.0-windows。同时也可以指定操作系统版本,例如net5.0-windows7或net5.0-windows10.0.17763.0(对于Windows October 2018 Update)。 ? ?如果要使用WinRT API,则需要定位Windows 10版本。 ? ?总结一下:
? 3.?WinRT Interop的重大改进 ? ?在以Windows API为目标这一主题上,微软已经移至一个新模型,以作为.NET 5.0的一部分来支持WinRT API。这包括调用API(在任一方向上; CLR <==> WinRT),两个类型系统之间的数据封送处理以及打算在类型系统或ABI边界上统一对待的类型的统一(即“投影类型” ”,IEnumerable<T>并且IIterable<T>是示例)。 ? ?从.NET 5.0开始,原有的WinRT互操作体系已被移除。这是一个巨大的变化。这意味着使用WinRT和.NET Core 3.x的应用程序和库需要重新开发对接,并且不能按原样在.NET 5.0上运行。 ? ?使用WinRT API的库将需要多目标来管理.NET Core 3.1和.NET 5.0之间的这种差异。 ? ?未来,.NET 将依靠Windows中的WinRT团队提供的新CsWinRT工具。它生成基于C#的WinRT互操作程序集,可以通过NuGet交付该程序集。Windows团队正是针对Windows中的WinRT API所做的。希望将WinRT(在Windows上)用作互操作系统的任何人都可以使用该工具,以将本机API公开给.NET或将.NET API公开给本机代码。 ? ?关于CsWinRT工具,已经发布了1.0版本,具体可以参考链接:https://blogs.windows.com/windowsdeveloper/2020/11/10/announcing-c-winrt-version-1-0-with-the-net-5-ga-release/ ? ?4. .NET Native Export/ .NET 本地导出 ? ? 即本机二进制文件启用导出功能。 ? ?.NET 开发团队的Aaron Robinson一直在从事.NET Native Exports项目,该项目为将.NET组件作为本机库发布提供了更完整的体验。 ? ?.NET Native导出项目能够实现:
? ?类似的实现技术,还有:
? ?5. 事件管道 ? ?事件管道是在.NET Core 2.2中添加的新子系统和API,可以在任何操作系统上执行性能和其他诊断调查。 ? ?在.NET 5.0中,事件管道已得到扩展,以使事件探查器能够写入事件管道事件。 ? ?对于以前依靠ETW(在Windows上)监视应用程序行为和性能的分析探查器,来说是一个很好的方案和选择。 ? ?这里不做详细展开了。 ? ?6. 转储调试,Dump分析调试 ? ?调试托管代码需要了解托管对象和构造。数据访问组件(DAC)是运行时执行引擎的子集,该引擎具有这些构造的知识,并且可以在没有运行时的情况下访问这些托管对象。 ? ?现在,可以使用WinDBG或Windows在Windows上分析在Linux上收集的.NET Core进程转储dotnet dump analyze。 ? ?本次发布还增加了对从macOS上运行的.NET进程捕获ELF转储的支持。由于ELF不是lldbmacOS上的本机可执行文件(像这样的本地调试器将无法与这些转储一起使用)文件格式,因此我们将其设为启用功能。 ? ?要在macOS上支持转储收集,请设置环境变量COMPlus_DbgEnableElfDumpOnMacOS=1。可以使用来分析产生的转储dotnet dump analyze。 ? ?7. 打印环境信息 ? ?随着.NET扩展了对新操作系统和芯片体系结构的支持,有时需要一种打印环境信息的方法。.NET 5.0 创建了一个简单的.NET工具来执行此操作,称为dotnet-runtimeinfo。可以使用以下命令安装和运行该工具: dotnet tool install -g dotnet-runtimeinfo
dotnet-runtimeinfo
? ?? ? ?五、运行时和类库的提升 ? ? 1.?RyuJIT的代码质量提升 ? ? 2. GC垃圾回收
? ? ?整体总结一下,Server GC延迟更低了,CPU消耗更少、性能更好了。 ? ? ?3. Windows Arm64的支持 ? ? ?.NET应用程序现在可以在Windows Arm64上本机运行。在.NET Core 3.0中添加的对Linux Arm64的支持(对glibc和musl的支持)。使用.NET 5.0,可以在Windows Arm64设备(例如Surface Pro X)上开发和运行应用程序。也可以通过x86仿真在Windows Arm64上运行.NET Core和.NET Framework应用程序。但是本机运行Arm64具有更好的性能。 ? ? ?同时,.NET 5.0 SDK当前在Windows Arm64上不包含Windows桌面组件-Windows窗体和WPF。Windows Arm64上支持SDK,控制台和ASP.NET Core应用程序,但Windows桌面组件不支持。 ? ? ?4. Arm64性能优化 ? ? ?.NET 5.0 中主要针对Arm64平台做了以下优化:
? ? ?更多详细信息,请参见在.NET 5.0中提高Arm64性能。 ? ? ? 5.?P95 +延迟改进 ? ? ??Stack Overflow的一位工程师Nick Craver最近分享了他们升级.NET Core后,对延迟的改进: ? ? ??问题页面的展现时间中值从大约21毫秒(由于GC而有所增加)降至约15毫秒。 ? ? ? 第95个百分位数从?40ms下降到?30ms(相同测量)。第99位从?60ms降至?45ms。 ? ? ? .NET项目组的解读是这样的:固定对象一直是GC性能的长期挑战,因为它们会加速(或导致)内存碎片。.NET 5.0为固定对象添加了新的GC堆。该固定对象堆是基于这样的假设(以空间换时间),他们的存在会导致不相称的性能挑战极少数固定的对象。将固定的对象(尤其是由.NET库作为实现细节创建的对象)移动到唯一的区域是有意义的,而垃圾回收代的GC堆几乎没有或没有固定的对象,因此具有更高的性能。 ? ? ? ?6. 分层编译性能改进 ? ? ? ?关于分层编译,大家可以参考这个连接:https://devblogs.microsoft.com/dotnet/tiered-compilation-preview-in-net-core-2-1/ ? ? ? ?在.NET 5.0中对分层编译进行了两项重大改进。下面这2段有点复杂,也比较晦涩 ? ? ? 分层编译的主要机制是调用计数。一旦某个方法被调用了n次,运行时就会要求JIT以更高的质量重新编译该方法。从最早的性能分析中,发现采用计数机制太慢,但是没有找到解决该问题的直接方法。.NET 5.0中改进了分层JIT编译所使用的调用计数机制,以平滑启动期间的性能。在过去的发行版中,已经发现在进程生命周期的前10到15秒钟内,性能会发生不可预测的变化(主要是针对Web服务器)。目前应该已经解决了。 ? ? ?另一个性能挑战是对具有循环的方法使用分层编译。根本的问题是,您可以使用带有循环多次的循环的冷方法(仅调用一次或几次; $ lt; n)。我们称这种病理情况为“冷方法”。热循环”。可以想象Main应用程序的方法会发生这种情况。结果,默认情况下,我们禁用了带循环方法的分层编译。相反,使应用程序可以选择使用带循环的分层编译。在某些情况下看到了个位数的高性能改进后,PowerShell就是选择执行此操作的应用程序。 ? ? ?为了更好地解决循环问题,.NET 实现了栈上替换(OSR)。这类似于Java虚拟机具有的同名功能。OSR允许在方法执行过程中重新编译当前正在运行的方法执行的代码,而这些方法是“堆栈上”活动的。该功能目前处于试验和选择启用状态,并且仅在x64上可用。 ? ? ?要使用OSR,必须启用多个功能。目前.NET 5.0中没有启用OSR,这个功能尚未决定在生产环境中是否启用,所以这个技术点,了解即可。 ? ? ? 7. JSON序列化 System.Text.Json ? ? ? .NET 5.0 对System.Text.Json进行了显着改进,以提高性能和可靠性,同时API尽可能地和Newtonsoft.Json类似。它还包括对将JSON对象反序列化对record类型的支持。 ? ? ? 同时微软提供了System.Text.Json替换Newtonsoft.Json的迁移指南。该指南详细阐明了这两个API之间的关系。 ? ? ??如何从 Newtonsoft.Json 迁移到 System.Text.Json ? ? ?? ??六、应用程序部署 ? ??应用程序开发完成后,根据实际的需要,可能会部署到Web服务器,云服务或客户端计算机,或者使用Azure DevOps或GitHub Actions之类的服务进行CI/CD。 ? ? .NET 5.0专注于改善单个文件应用程序,减小docker多阶段构建的容器大小,并为使用.NET Core部署ClickOnce应用程序提供更好的支持。 ? ? 1. 容器 ? ??与容器的交互协作非常重要。这个版本中添加了OpenTelemetry支持,可以从应用程序中捕获分布式跟踪和指标。dotnet-monitor是一个新工具,可以作为从.NET进程访问诊断信息的主要工具。特别是,我们已经开始构建dotnet-monitor的容器变体,您可以将其用作应用程序sidecar。同时,.NET项目组正在构建dotnet / tye,以提高微服务开发人员在开发和部署到Kubernetes环境中的效率。 ? ?.NET运行时现在支持cgroup v2,这个API预计将在2020年以后成为与容器相关的重要API。Docker当前使用cgroup v1(.NET已支持)。相比之下,cgroup v2比cgroup v1更简单,更有效且更安全。.NET 5.0将在cgroup v2环境中正常工作。 ? ?除了Nano Server,微软还将发布Windows Server Core映像,努力减小Windows Server Core映像的大小。 ? ??更小的体积、更低的成本、更快的启动性能。.NET 5.0中将SDK映像重新建立在ASP.NET映像之上,而不是buildpack-deps,这样可以显着减小在多阶段构建方案中提取的聚合映像的大小。 ? ? ? ? ? 2. 单文件应用? ?? ? ? 单个文件应用程序作为单个文件发布和部署。该应用程序及其依赖项都包含在该文件中。当应用程序运行时,依赖项直接从该文件加载到内存中(不影响性能)。 ? ? 在.NET 5.0中,单个文件应用程序主要集中在Linux上。它们可以是框架相关的,也可以是独立的。依赖于全局安装的.NET运行时,依赖于框架的单个文件应用程序可能很小。自包含的单文件应用程序较大(由于带有运行时),但不需要作为安装前步骤就安装.NET运行时,因此可以正常工作。通常,依赖框架对开发和企业环境有利,而对于ISV,独立包含通常是更好的选择。 ? ? .NET Core 3.1制作了一个单文件应用程序版本。它将二进制文件打包到一个文件中以进行部署,然后将这些文件解压缩到一个临时目录中以加载并执行它们。在某些情况下,这种方法会更好,但是希望为5.0构建的解决方案将是首选,并且会受到欢迎。?? ? ? 可以使用以下命令来生成单文件应用程序: 框架相关的单文件应用程序:
dotnet publish -r linux-x64 --self-contained false /p:PublishSingleFile=true
自包含的单文件应用程序:
dotnet publish -r linux-x64 --self-contained true /p:PublishSingleFile=true
3. ClickOnce ? ? ClickOnce一直是流行的.NET部署选项,历史也比较悠久了。.NET Core 3.1和.NET 5.0 Windows应用程序现在支持它。? ? ? ?? ? ? ?以上是.NET 5.0 发布后的技术梳理和整理,.NET 5.0作为.NET技术栈上近几年一个重量级的里程碑,是All in one,统一平台的第一个版本。现在有微软的背书,微软从.NET Preview 1就开始在自己的网站上运行.NET 5,(Bing.com、dot.net已升级并运行了数个月),同时早期的.NET Core版本可以直接升级到.NET 5. 所以大家可以放心使用的。我们也会逐渐将部分应用迁移升级到.NET 5.0. 以上是本次的一个分享。 ? ? 参考链接: ? ?https://devblogs.microsoft.com/dotnet/announcing-net-5-0/ ? ?https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/#json ? ?https://blogs.windows.com/windowsdeveloper/2020/11/10/announcing-c-winrt-version-1-0-with-the-net-5-ga-release/ ? 周国庆 2020/11/15 ? ? ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc – 服务层是否可以访问HttpContext?
- asp.net-mvc-3 – MVC 3上的单元测试控制器为结果返回null,
- asp.net-mvc – .net Mvc 3 Ajax.BeginForm,获取表单元素
- 在ASP.NET中开发SharePoint Web部件
- asp.net – 当使用HttpContextScoped()时,StructureMap不会
- asp.net-mvc – 概念类型中的成员数量不匹配 – 但确实如此
- 如何使用asp.net中的“发布/重定向/获取”a.k.a.“重定向后
- asp.net-identity – 使用SQL Server而不是LocalDB的Web AP
- .net – FileLoadException:无法加载文件或程序集System.R
- 是否值得在ASP.NET中使用PLINQ?
- razor – MVC3到MVC4 RTM手动升级问题:@在此关键
- asp.net-mvc – ASP.NET MVC 4“DictionaryValue
- asp.net-mvc-4 – .NET Web API Post Action返回
- ASP.NET OutputCache和Cookies
- 将本地化的resources.resx文件转换为asp.net MVC
- ASP.NET Core使用NLog记录日志
- ASP.NET webform的Bootstrap
- ASP.NET EF实体主外键关系
- asp-classic – 如何在经典的asp web应用程序中生
- asp.net-mvc – 如何在ASP.NET MVC中维护Html.Ch