为什么List 。OrderBy LINQ比IComparable + List 更快。在Debug模式下排序?

我感兴趣的是使用LINQ对类进行排序,或者实现IComparable接口和List.Sort是否会更快。 当LINQ代码更快时,我感到非常惊讶。

为了进行测试,我创建了一个非常简单的类,其中包含不太合适的TestSort名称,实现了IComparable。

class TestSort: IComparable { private int age; private string givenName; public int Age { get { return age; } set { age = value; } } public string GivenName { get { return givenName; } set { givenName = value; } } public TestSort(int age, string name) { this.age = age; this.givenName = name; } public int CompareTo(TestSort other) { return this.age.CompareTo(other.age); } } 

然后是一个简单的程序来对它进行多次排序 – 排序比复制列表要昂贵得多,因此可以忽略它的效果。

 class Program { static void Main(string[] args) { // Create the test data string name = "Mr. Bob"; Random r = new Random(); var ts2 = new List(); for (int i = 0; i < 100; i++) { ts2.Add(new TestSort(r.Next(), name)); } DateTime start, end; // Test List.Sort start = DateTime.Now; for (int i = 0; i < 100000; i++) { var l = ts2.ToList(); l.Sort(); } end = DateTime.Now; Console.WriteLine("IComparable: "); Console.WriteLine((end - start).TotalMilliseconds); // Test Linq OrderBy start = DateTime.Now; for (int i = 0; i  item.Age).ToList(); } end = DateTime.Now; Console.WriteLine("\nLINQ: "); Console.WriteLine((end - start).TotalMilliseconds); Console.WriteLine("Finished."); Console.ReadKey(); } } 

我收到以下输出后感到非常惊讶:

 IComparable: 2965.1696 LINQ: 2181.1248 

有时LINQ会低于2000,有时IComparable会高达3000。

当我使用普通的List测试时, List.Sort的速度是LINQ的1/4,大约是2000。

那么为什么LINQ的速度只有我class级正常速度的66%? 我在实施IComparable时遇到了什么问题吗?

更新:我只是想在发布模式下尝试这样做,是的,结果是不同的:

 IComparable: 1593.0911 Linq: 1958.1119 

但是我仍然非常有兴趣知道为什么IComparable在调试模式下会变慢。

如果在开始测量之前确保所有内容都是JITed,则可能会得到不同的结果(我还建议使用Stopwatch类来测量时间):

 var ll = ts2.ToList(); ll.Sort(); ll.OrderBy(item => item.Age).ToList(); 

根据我的测量结果(添加上面的代码之后),IComparable总是更快(即使在调试中)。

Sort使用未经优化的quicksort,在最坏的情况下具有* n复杂性。 我不知道orderby使用了什么,但我知道它不使用相同的方法,因为它是一个稳定的排序,不像array.sort

对我来说,我将使用Linq和IComparable(当这是最多或唯一的排序方式)。 在这种情况下,item是TestSort: IComparable

 var sorted = ll.OrderBy(item => item); // This automatically used age to compare, as it's defined in CompareTo 

ll可以是任何IEnumerable:List,Array等。

另外在CompareTo你可以有多种方式进行比较…例如,你可以这样做:

  public int CompareTo(TestSort other) { return this.age != other.age ? this.age.CompareTo(other.age) : this.dateOfBirth.CompareTo(other.dateOfBirth); } 

这可能是调用方法CompareTo的开销,当编译并在发布模式下运行时,它将被内联替换。