为什么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
的开销,当编译并在发布模式下运行时,它将被内联替换。