簡體   English   中英

為什么OrderBy返回IOrderedEnumerable <T> 比排序快得多?

[英]Why is OrderBy which returns IOrderedEnumerable<T> much faster than Sort?

這是這個出色的問題C#Sort和OrderBy比較的后續。 我將使用相同的示例:

List<Person> persons = new List<Person>();
persons.Add(new Person("P005", "Janson"));
persons.Add(new Person("P002", "Aravind"));
persons.Add(new Person("P007", "Kazhal"));

爭用的方法是:

persons.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true));
//and
persons.OrderBy(n => n.Name);

首先,我要說的是,我了解沒有任何明顯的性能差異可擔心。 但是我很想知道為什么OrderBy的性能要比Sort好得多。 我使用@phoog在原始問題中發布的答案。

private void button1_Click(object sender, EventArgs e)
{
    IEnumerable<Person> people;

    BenchMark(persons => persons.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true)));

    BenchMark(persons => people = persons.OrderBy(n => n.Name));
}

private static Random randomSeed = new Random();
public static string RandomString(int size, bool lowerCase)
{
    var sb = new StringBuilder(size);
    int start = (lowerCase) ? 97 : 65;
    for (int i = 0; i < size; i++)
    {
        sb.Append((char)(26 * randomSeed.NextDouble() + start));
    }
    return sb.ToString();
}

private static void BenchMark(Action<List<Person>> action)
{
    List<Person> persons = new List<Person>();
    for (int i = 0; i < 10000; i++)
    {
        persons.Add(new Person("P" + i.ToString(), RandomString(5, true)));
    }
    List<Person> unsortedPersons = new List<Person>(persons);

    Stopwatch watch = new Stopwatch();
    for (int i = 0; i < 100; i++)
    {
        watch.Start();

        action(persons);

        watch.Stop();
        persons.Clear();
        persons.AddRange(unsortedPersons);
    }

    MessageBox.Show(watch.Elapsed.TotalMilliseconds.ToString());
}

結果:

Sort() => 3500 ~ 5000 ms
OrderBy() => 0.2 ~ 1.5 ms

盡管即使我最初測試的列表較小,差異仍然很大,但隨着收藏數量的增加,它變得越來越耀眼。 可能是我缺少了解.NET集合的關鍵因素,但是我的想法是,由於Sort作用於現有的List<T> ,因此與OrderBy相比,它在處理上的開銷(如果有的話)應該更少List<T>在本例persons ),但要返回另一個集合IOrderedEnumerable<T> 但是OrderBy性能仍然要好得多。 IEnumerable<T>類型相比, List<T>可能具有一定的開銷,但是無論如何, Sort都將對現有列表起作用! 此外,我不覺得看到Linq方法比現有的.NET方法運行得更快而感到高興。

原始問題中的所有答案都將“ Sort與“ OrderBy.ToList進行比較,我認為這會產生一些開銷,因此其性能大致相同。

實施上可能有什么區別?


編輯:好的,我學到了一些新東西。 這是我確認有關延遲執行的方式。

private void button1_Click(object sender, EventArgs e)
{
    BenchMark(persons =>
    {
        persons.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true));
        foreach (var item in persons)
        {
            break;
        }
    });

    BenchMark(persons =>
    {
        IEnumerable<Person> people = persons.OrderBy(n => n.Name);
        foreach (var item in people)
        {
            break;
        }
    });
}

SortOrderBy運行,而OrderBy在5000ms以上運行。 所以確實我的結論是錯誤的。 一旦我開始枚舉集合,他們兩個人的表現就相等。 我更喜歡OrderBy的語法:)

編輯2:我剛剛發現這是復制品的完全相同。 但這是一個關於延遲執行更有趣的問題,盡管不是完全有關順序的。

在這種情況下, OrderBy快得多,因為您實際上沒有執行它。

在您枚舉結果之前,查詢將被推遲 ,因此它從未真正進行過排序。 在實際枚舉結果之前, IOrderedEnumerable<T>不會處理輸入,也不執行任何形式的排序。

嘗試將基准更改為:

 BenchMark(persons => people = persons.OrderBy(n => n.Name).Count());

Count()調用將強制排序實際發生(因為它需要枚舉IOrderedEnumerable<T>來生成一個計數),這應該使您的時間顯着平衡。

大多數LINQ擴展方法都是以這種方式工作的-在您枚舉它們之前(通過Count() ,調用ToList()或僅在常規的foreach循環中使用它們等),它們的影響可以忽略不計,因為它們實際上沒有做任何事情除了構建可枚舉對象外,直接進行其他操作。 其他基准與OrderBy(...).ToList()相比的原因是,添加ToList()強制OrderBy完全執行並實際對結果進行排序。

與大多數LINQ方法一樣, OrderBy()使用延遲執行。

在枚舉其結果之前,它實際上不會做任何事情。

要正確衡量其性能,可以調用.OrderBy(...).Count()

OrderBy()不會創建排序列表。

它創建一個IEnumerable對象,當您枚舉該對象時,將生成一個排序列表。 枚舉列表之前,不會進行實際排序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM