【问题标题】:Why is List<>.OrderBy LINQ faster than IComparable+List<>.Sort in Debug mode?为什么 List<>.OrderBy LINQ 在调试模式下比 IComparable+List<>.Sort 快?
【发布时间】:2010-07-26 10:45:09
【问题描述】:

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

为了进行测试,我创建了一个非常简单的类,名称为 TestSort,实现 IComparable。

class TestSort: IComparable<TestSort>  {
    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<TestSort>();

        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<T>: ");
        Console.WriteLine((end - start).TotalMilliseconds);


        // Test Linq OrderBy
        start = DateTime.Now;
        for (int i = 0; i < 100000; i++) {
            var l = ts2.ToList();
            l = l.OrderBy(item => item.Age).ToList();
        }
        end = DateTime.Now;

        Console.WriteLine("\nLINQ: ");
        Console.WriteLine((end - start).TotalMilliseconds);

        Console.WriteLine("Finished.");
        Console.ReadKey();
    }
}

我很惊讶收到以下输出:

IComparable<T>:
2965.1696

LINQ:
2181.1248

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

当我用普通的List&lt;Int&gt; 测试它时,List.Sort 的速度是 LINQ 的 1/4,保持在 2000 左右。

那么,为什么 LINQ 对于我的班级来说只有正常排序速度的 66% 左右?我的 IComparable 实现有问题吗?

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

IComparable<T>:
1593.0911

Linq:
1958.1119

但我仍然很想知道为什么 IComparable 在调试模式下速度较慢。

【问题讨论】:

  • 您是否尝试在调试模式(项目属性)中设置优化并查看它是否仍然较慢?如果不是,那可以解释它。
  • 优化代码已打开...我正在寻找实际原因而不是促成因素。我不是要解决这个问题,这两种方法对我的目的来说都足够快,我只是想知道为什么。

标签: c# linq sorting benchmarking


【解决方案1】:

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

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

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

【讨论】:

  • 如何确保在测量之前对事物进行 JIT 处理?
  • 还有。在我的 PC 上进行了大约 900 次测试,IComparable 速度更快。但是如果我循环超过 1000 个,那么 LINQ 会变得更快。因此,初始 LINQ 设置有一些开销,但重复使用最终会更快。
  • 在代码sn-p中,当你调用ll.OrderBy()时,列表已经排在了上一行,所以OrderBy()时可能需要进行的计算较少叫做。您能否验证在您的秒表测试中,您没有在已排序的列表上调用OrderBy()
  • @lorddev 此代码仅用于 JIT 方法,因此实际测量会更准确。然而,这些天来,最好只使用BenchmarkDotNet
【解决方案2】:

对我来说,我会将 Linq 与 IComparable 一起使用(当这是最多或唯一的排序方式时)。在这种情况下,项目是TestSort: IComparable&lt;TestSort&gt;

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);
    }

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • Linq to objects OrderBy 使用稳定的快速排序,而 Array.Sort 使用不稳定的快速排序。算法的速度成本应该没有太大差异。它们都是 O(n log n)。
    • 你知道它是优化过还是还是同样的n^2最坏情况?
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2015-07-24
      • 1970-01-01
      • 2014-07-29
      • 2011-05-01
      • 2013-05-28
      • 1970-01-01
      相关资源
      最近更新 更多