繁体   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