与 LINQ 相比,为啥 Array.Sort() 这么慢?

Posted

技术标签:

【中文标题】与 LINQ 相比,为啥 Array.Sort() 这么慢?【英文标题】:Why is Array.Sort() so slow compared to LINQ?与 LINQ 相比,为什么 Array.Sort() 这么慢? 【发布时间】:2012-05-05 04:21:14 【问题描述】:

我制作了快速测试应用程序来比较 LINQ 排序和我的自定义对象上的 Array.Sort。 Array.Sort 似乎非常慢!

我的自定义类是这样的:

class Person : IComparable<Person>

    public int Age  get; set; 
    public string Name  get; set; 

    public int CompareTo(Person obj)
    
        return this.Age.CompareTo(obj.Age);
    

    public Person()
     


然后我在 main() 中做了我的测试人员:

string name = "Mr. Tomek";

Random r = new Random();
int size = 10000000;

DateTime start, end;
Person[] people1 = new Person[size];
Person[] people2 = new Person[size];

for (int i = 0; i < size; i++)

     people1[i] = new Person();
     people1[i].Age = r.Next(0, 10000);
     people1[i].Name = name;

     people2[i] = new Person();
     people2[i].Age = people1[i].Age;
     people2[i].Name = people1[i].Name;

之后,我测量了按 Array.Sort 和 LINQ 排序所花费的时间:

start = DateTime.Now;
var sort = from s in people2
           orderby s.Age
           select s;
end = DateTime.Now;
Console.WriteLine("LINQ: ");
Console.WriteLine((end - start).TotalMilliseconds);

start = DateTime.Now;
Array.Sort(people1,((Person p1, Person p2)=>return p1.CompareTo(p2);));
end = DateTime.Now;

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

Console.ReadLine();

Linq 时间:大约 1 或 2 毫秒

Array.Sort:超过 16 个 SECONDS!

所有数组都已排序(LINQ 生成新集合,原始数组未排序)但 Array.Sort 非常慢!怎么解释? (在 DEBUG 和 RELEASE 模式下 Array.Sort 极度失败)

我在使用 Array.Sort 排序时粘贴了带有 lambda 表达式的代码,但无论有没有它都是一样的。 (类 Person 实现 IComparable 接口)

【问题讨论】:

您可能对我的相关问题感兴趣。 ***.com/questions/10110013/… @TomaszSikora:您可以通过调用Array.Sort(people1) 进行简单排序,因为自动使用IComparable&lt;T&gt; 实现。 我确实注意到了一些事情...... Linq 在对更大的数组进行排序时更快。当 Array 少于 100 000 个元素时,Array.Sort 更快。为什么会这样? 这里要理解的关键是查询表达式的结果是一个查询。它不是查询的结果。另外:使用秒表计时,而不是 DateTime.Now。您将获得更准确和更精确的结果。 请使用秒表来获得更准确的时间读数。 ***.com/questions/28637/… 【参考方案1】:

您的 Linq 查询甚至没有被执行,因为您没有得到结果。这称为deferred execution。仅当您实际枚举结果时才会执行查询。

使用var results = sort.ToArray()之类的东西来执行查询,你会得到更准确的结果。

【讨论】:

不执行的代码总是会胜过正在执行的代码! 我希望 OP 不会觉得自己很傻。这是我见过的一个非常常见的问题/错误(可能我自己也做过):不知道或不理解您何时实际枚举 IEnumerable 以及何时更改它。我认为比这更常见的是通过多次枚举 IEnumerable 来降低效率的问题。 @blesh 是的,这肯定不是人们了解 Linq 的第一件事 :)【参考方案2】:

LINQ 是懒惰的。你的people2 实际上并没有被排序,LINQ 只是创建了一个临时的“promise 对象”,它将被排序。要让它真正发生,你必须通过Console.WriteLine 强制评估排序结果,将其转换为列表/数组或执行其他类似操作。

查看更多:deferred execution。

【讨论】:

【参考方案3】:

Linq 语句返回 IEnumerable&lt;T&gt; 或类似的形式,此(或任何使用 yield 关键字的内容)仅在您 迭代 时执行。 Linq 库中提供的大多数操作(不是全部)are lazy / deferred。

你没有迭代它,所以你实际上并没有执行排序。

您需要强制进行完整的迭代。将结果粘贴在 List 中将完全迭代返回的枚举:

var sort = (from s in people2
            orderby s.Age
            select s).ToList();

只有这样你才能比较苹果和苹果。

事实上,在排序的情况下(orderby),只需选择第一个项将导致完全迭代,因为在返回第一个结果之前需要完全完成排序:

var sort = from s in people2
           orderby s.Age
           select s;

var s = sort.First();

【讨论】:

【参考方案4】:

尝试更改此部分并再次进行测试。

    start = DateTime.Now;
    var sort = (from s in people2
               orderby s.Age
               select s).ToList();
    end = DateTime.Now;

这将评估 LINQ 表达式。

【讨论】:

以上是关于与 LINQ 相比,为啥 Array.Sort() 这么慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥没有参数的函数(与实际函数定义相比)编译?

为啥在这个例子中 LINQ 更快

与 CGContextDrawImage 相比,为啥 UIImageView 如此占用内存

c#中array.sort()用法

为啥 NegativeBinomialP 与 R 相比给出不同的系数?

为啥声明表变量与临时表相比非常慢?