.Net Core 3.1 中的 IEnumerable.OrderBy().First() 优化是不是记录在任何地方?

Posted

技术标签:

【中文标题】.Net Core 3.1 中的 IEnumerable.OrderBy().First() 优化是不是记录在任何地方?【英文标题】:Is the IEnumerable.OrderBy().First() optimisation in .Net Core 3.1 documented anywhere?.Net Core 3.1 中的 IEnumerable.OrderBy().First() 优化是否记录在任何地方? 【发布时间】:2021-02-16 07:34:35 【问题描述】:

其中一个 .Net Core 版本(我不确定是哪个)引入了优化,如果您编写这样的代码:

int smallest = new[] 7, 2, 4, 6, 0, 1, 6, 9, 8 .OrderBy(i => i).First();

那么它的复杂度是O(N) 而不是O(N.Log(N))

这在任何地方都有记录吗?如果它不是“官方”的,我不想依赖这种优化。


显示 .Net Core 和 .Net Framework 之间差异的示例代码:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo

    static class Program
    
        static void Main()
        
            int[] test =  7, 2, 4, 6, 0, 1, 6, 9, 8 ;

            var comparer = new Comparer();
            var _ = test.OrderBy(i => i, comparer).First();
        
    

    class Comparer : IComparer<int>
    
        public int Compare(int x, int y)
        
            Console.WriteLine($"Comparing x with y");
            return x.CompareTo(y);
        
    

使用 .Net Framework 在线试用:https://dotnetfiddle.net/XItXYL

使用 .Net Core 在线试用:https://dotnetfiddle.net/swlc0O

.Net Framework 4.8 的输出:

Comparing 0 with 7
Comparing 0 with 8
Comparing 0 with 9
Comparing 0 with 6
Comparing 0 with 1
Comparing 0 with 0
Comparing 0 with 2
Comparing 0 with 6
Comparing 0 with 4
Comparing 0 with 2
Comparing 0 with 0
Comparing 7 with 2
Comparing 7 with 4
Comparing 7 with 6
Comparing 7 with 7
Comparing 7 with 8
Comparing 7 with 9
Comparing 7 with 6
Comparing 7 with 1
Comparing 7 with 7
Comparing 7 with 1
Comparing 9 with 7
Comparing 9 with 9
Comparing 9 with 8
Comparing 7 with 7
Comparing 7 with 8
Comparing 7 with 7
Comparing 6 with 2
Comparing 6 with 4
Comparing 6 with 6
Comparing 6 with 1
Comparing 6 with 6
Comparing 6 with 6
Comparing 6 with 1
Comparing 6 with 6
Comparing 6 with 6
Comparing 4 with 2
Comparing 4 with 4
Comparing 4 with 1
Comparing 2 with 2
Comparing 2 with 1

.Net Core 3.1 的输出:

Comparing 2 with 7
Comparing 4 with 2
Comparing 6 with 2
Comparing 0 with 2
Comparing 1 with 0
Comparing 6 with 0
Comparing 9 with 0
Comparing 8 with 0

【问题讨论】:

我挖的东西github.com/dotnet/runtime/issues/14867github.com/dotnet/corefx/pull/2401 OrderBy 后跟 Count() 也几乎立即运行……微软是否发明了 O(1) 排序算法?” - 引用自 this blog 在 2017 年 还有github.com/dotnet/docs/pull/19949/files/… OrderBy() + Count() 优化(实际上是Select() + Count())是一个完美的例子,说明了为什么这个问题很重要。阅读文章末尾附近的内容,它被确定为一项重大更改(来自Select() 的副作用丢失)。有一个未讨论的修复参考,但可能会回滚优化。这也是为什么这个问题重要的一个例子。性能指标最好使用分析和作为单元测试的一部分来处理。编写您需要编写、测试和分析的代码以识别问题并首先对其进行优化。 @mm8 我希望基本的排序和搜索操作能够记录其复杂性。例如,the documentation for List&lt;T&gt;.Sort() 声明它是一个O(N.Log(N)) 操作。如果没有这样的保证,我不得不使用.MaxBy() 扩展名,而不是使用.OrderBy().First()。事实上,这就是我提出问题的全部理由! 【参考方案1】:

“是否记录了这种优化”问题的答案是:是(有点)。

有关讨论和实现它的 GitHub 提交的链接,请参见 https://github.com/dotnet/runtime/issues/14867。

【讨论】:

【参考方案2】:

Microsoft 文档中没有正式记录这些 LINQ 运算符(OrderBy 和 First)。

这是故意的。一旦以这种方式正式记录某个行为,对该行为的任何更改都会成为重大更改,这可能会限制开发人员进行其他可能更有益的优化的能力。如果你打算依赖具体的实现细节,你可能应该为此编写自己的方法。

也就是说,O(n)O(n log(n)) 的复杂性在应用程序中区分可接受和不可接受的性能是比较少见的。仔细考虑您是否正在进行过早优化。

【讨论】:

以上是关于.Net Core 3.1 中的 IEnumerable.OrderBy().First() 优化是不是记录在任何地方?的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core 3.1 中的依赖注入具有多种实现 [重复]

忽略 ASP.NET Core 3.1 中的 WCF 证书错误

Asp.net core 3.1 中的路由

如何更改 .NET Core 3.1 API 中的路由错误

如何从 .NET Core 3.1 中的 F# 访问 WCF 服务?

.net core 3.1 中的 CORS 阻止了 Httppost 和 httpput