在.NET Core之前的版本中,系统出现了大量的变动。Linq代码基,特别是提高性能。这个流程已经放缓了,但是.NET 5仍然可以看到LINQ的性能改进。
OrderBy有一个值得注意的改进。正如前面所讨论的,将coreclr的本地排序实现转换为托管代码有多种动机,其中一个就是能够轻松地将其作为基于spanc的排序方法的一部分进行重用。这样的api是公开的,并且通过,我们能够在System.Linq中利用基于spane的排序。这特别有好处,因为它支持利用基于Comparison的排序例程,这反过来又支持避免在每个比较操作上的多层间接。
Sort .NET FW 4.8 100.78 us 1.00
Sort .NET Core 3.1 101.03 us 1.00
Sort .NET 5.0 85.46 us 0.85
对于一行更改来说,这还不错。
另一个改进是来自@timandy的dotnet/corefx#41342。PR可扩充的枚举。SkipLast到特殊情况IList以及内部IPartition接口(这是各种操作符相互之间进行优化的方式),以便在可以廉价确定源长度时将SkipLast重新表示为Take操作。
SkipLast .NET Core 3.1 1,641.0 ns 1.00 248 B
SkipLast .NET 5.0 684.8 ns 0.42 48 B
最后一个例子,dotnet/corefx#40377是一个漫长的过程。这是一个有趣的例子。一段时间以来,我看到开发人员认为Enumerable.Any()比Enumerable.Count() != 0更有效;毕竟,Any()只需要确定源中是否有东西,而Count()需要确定源中有多少东西。因此,对于任何合理的集合,any()在最坏情况下应该是O(1),而Count()在最坏情况下可能是O(N),那么any()不是总是更好的吗?甚至有Roslyn分析程序推荐这种转换。不幸的是,情况并不总是这样。在。net 5之前,Any()的实现基本如下:
这意味着在通常情况下,即使可能是O(1)操作,也会导致分配一个枚举器对象以及两个接口分派。相比之下,自从. net Framework 3.0中LINQ的初始版本发布以来,Count()已经优化了特殊情况下ICollection使用它的Count属性的代码路径,在这种情况下,它通常是O(1)和分配自由,只有一个接口分派。因此,对于非常常见的情况(比如源是List),使用Count() != 0实际上比使用Any()更有效。虽然添加接口检查会带来一些开销,但值得添加它以使Any()实现具有可预测性并与Count()保持一致,这样就可以更容易地对其进行推理,并使有关其成本的主流观点变得正确。
如今,网络是几乎所有应用程序的关键组件,而良好的网络性能至关重要。因此,.NET的每一个版本都在提高网络性能上投入了大量的精力.NET 5也不例外。
让我们先看看一些原语,然后继续往下看。系统。大多数应用程序都使用Uri来表示url,它的速度要快,这一点很重要。许多PRs已经开始在。.NET 5中使Uri更快。可以说,Uri最重要的操作是构造一个Uri,而dotnet/runtime#36915使所有Uri的构造速度更快,主要是通过关注开销和避免不必要的开销:
Ctor .NET FW 4.8 443.2 ns 1.00 225 B
Ctor .NET Core 3.1 192.3 ns 0.43 72 B
Ctor .NET 5.0 129.9 ns 0.29 56 B