簡體   English   中英

這個LINQ性能來自哪里?

[英]Where does this LINQ performance come from?

我做了一個函數來遞歸地找到適合條件的第一個或默認項(第一個代碼塊)。

Resharper建議我只在一個LINQ行(第二個代碼塊)中更改幾行。

我想知道Resharper的建議是否會給我相同的性能和相同的內存占用。 我對性能進行了測試(第3代碼塊)。 結果就是我的預期。 為什么差異如此之大?

8156 milliseconds
Laure
23567 milliseconds
Laure LINQ

那個差異來自哪里? 為什么結果不一樣?......或者至少更接近?

public static T RecursiveFirstOrDefault<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
    where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
    if (item == null)
    {
        return null;
    }

    if (condition(item))
    {
        return item;
    }

    foreach (T child in childrenSelector(item))
    {
        T result = child.RecursiveFirstOrDefault(childrenSelector, condition);
        if (result != null)
        {
            return result;
        }
    }

    return null;
}

但是Resharper建議我將foreach塊轉換為LINQ查詢,如下所示:

public static T RecursiveFirstOrDefaultLinq<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
    where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
    if (item == null)
    {
        return null;
    }

    if (condition(item))
    {
        return item;
    }

    // Resharper change:
    return childrenSelector(item).Select(child => child.RecursiveFirstOrDefaultLinq(childrenSelector, condition)).FirstOrDefault(result => result != null);
}

測試:

private void ButtonTest_OnClick(object sender, RoutedEventArgs e)
{
    VariationSet varSetResult;
    Stopwatch watch = new Stopwatch();

    varSetResult = null;
    watch.Start();
    for(int n = 0; n < 10000000; n++)
    {
        varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefault((varSet) => varSet.VariationSets,
            (varSet) => varSet.Name.Contains("Laure"));
    }
    watch.Stop();
    Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
    Console.WriteLine(varSetResult.Name);

    watch.Reset();

    varSetResult = null;
    watch.Start();
    for(int n = 0; n < 10000000; n++)
    {
        varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefaultLinq((varSet) => varSet.VariationSets,
            (varSet) => varSet.Name.Contains("Laure"));
    }
    watch.Stop();
    Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
    Console.WriteLine(varSetResult.Name + " LINQ");

}

我今天必須去...希望正確回答測試:x86,在12核機器上發布,Windows 7,Framework.Net 4.5,

我的結論:

在我的情況下,非linq版本的速度提高約3倍。 LINQ中的可讀性更好但是誰在關注它何時只能記住它的作用以及如何調用它(在這種情況下 - 不是一般的絕對情況)。 LINQ幾乎總是比良好的編碼方法慢。 我會個人風味:

  • LINQ:在特定項目代碼中,性能不是一個問題(大多數情況下)
  • Non Linq:性能在特定項目代碼中存在的問題,以及在庫中使用的地方以及代碼應該穩定和固定的地方,應該很好地記錄方法的使用,我們不應該真正挖掘內部。

以下是非LINQ和LINQ代碼性能之間存在差異的一些原因:

  1. 每次調用方法都會產生一些性能開銷。 必須將信息壓入堆棧,CPU必須跳轉到不同的指令行等。在LINQ版本中,您調用Select和FirstOrDefault,而您在非LINQ版本中沒有這樣做。
  2. 當您創建Func<>以傳遞到Select方法時,會有時間和內存的開銷。 當您在基准測試中多次乘以內存開銷時,可能會導致需要更頻繁地運行垃圾收集器,這可能很慢。
  3. 您正在調用的Select LINQ方法生成一個表示其返回值的對象。 這也增加了一點內存消耗。

差異為何如此之大?

它實際上並不那么大。 沒錯,LINQ的使用時間延長了50%,但老實說,你所說的只是能夠在一毫秒內完成整個遞歸操作400次。 這並不慢,你不可能注意到這種差異,除非這是你在視頻游戲等高性能應用程序中一直在做的操作。

暫無
暫無

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

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