总结VS在LINQ性能总和 [英] Aggregate vs Sum Performance in LINQ

查看:94
本文介绍了总结VS在LINQ性能总和的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

找到一个的IEnumerable<的总和三种不同的实现; int>的源下面,当源拥有10000整数的时间一起被给予的。

Three different implementations of finding the sum of an IEnumerable < int> source are given below along with the time taken when the source has 10,000 integers.

source.Aggregate(0, (result, element) => result + element);  



需要3毫秒

takes 3 ms

source.Sum(c => c);



需要12毫秒

takes 12 ms

source.Sum();



需要1毫秒

takes 1 ms

我想知道为何在第二实施四倍比第一个更昂贵。 。难道不应该是一样的第三个执行

I am wondering why the second implementation is four times more expensive than the first one. Shouldn't it be same as the third implementation.

推荐答案

请注意:我的电脑运行的是.NET 4.5 RC,所以这是可能的我的结果受此影响。

Note: My computer is running .Net 4.5 RC, so it's possible that my results are affected by this.

测量它需要执行的方法只有一次的时间通常不是非常有用。它可以通过类似的事情JIT编译,这是不是在真正的代码,实际的瓶颈很容易控制。正因为如此,我测执行每个方法100×(在Release模式没有调试附后)。我的结果是:

Measuring the time it takes to execute a method just once is usually not very useful. It can be easily dominated by things like JIT compilation, which are not actual bottlenecks in real code. Because of this, I measured executing each method 100× (in Release mode without debugger attached). My results are:


  • 骨料():9毫秒

  • 总和(拉姆达):12毫秒

  • 总和():6毫秒

  • Aggregate(): 9 ms
  • Sum(lambda): 12 ms
  • Sum(): 6 ms

事实上,总和()是最快的是并不奇怪:它包含一个简单的循环没有任何委托调用,这是非常快的。之间的差异总和(拉姆达)骨料()是几乎没有,你测得什么突出,但它仍然是那里。可能是什么的原因吧?让我们来看看反编译代码的两种方法:

The fact that Sum() is the fastest is not surprising: it contains a simple loop without any delegate invocations, which is really fast. The difference between Sum(lambda) and Aggregate() is not nearly as prominent as what you measured, but it's still there. What could be the reason for it? Let's look at decompiled code for the two methods:

public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
{
    if (source == null)
        throw Error.ArgumentNull("source");
    if (func == null)
        throw Error.ArgumentNull("func");

    TAccumulate local = seed;
    foreach (TSource local2 in source)
        local = func(local, local2);
    return local;
}

public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
{
    return source.Select<TSource, int>(selector).Sum();
}



正如你所看到的,骨料()使用一个循环,但总和(拉姆达)使用选择(),这反过来又使用了迭代​​器。并使用迭代器意味着有一些开销:在创建迭代器对象(可能是更重要的),每个项目多了一个方法调用。

As you can see, Aggregate() uses a loop but Sum(lambda) uses Select(), which in turn uses an iterator. And using an iterator means there is some overhead: creating the iterator object and (probably more importantly) one more method invocation for each item.

让我们验证,使用选择()实际上是写原因,我们自己的总和(拉姆达)两次,第一次使用选择( ),它应该表现一样的总和(拉姆达)从框架,一旦不使用选择()

Let's verify that using Select() is actually the reason by writing our own Sum(lambda) twice, once using Select(), which should behave the same as Sum(lambda) from the framework, and once without using Select():

public static int SlowSum<T>(this IEnumerable<T> source, Func<T, int> selector)
{
    return source.Select(selector).Sum();
}

public static int FastSum<T>(this IEnumerable<T> source, Func<T, int> selector)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (selector == null)
        throw new ArgumentNullException("selector");

    int num = 0;
    foreach (T item in source)
        num += selector(item);
    return num;
}



我的测量结果证实了我的想法:

My measurements confirm what I thought:


  • SlowSum(拉姆达):12毫秒

  • FastSum(拉姆达):9毫秒

  • SlowSum(lambda): 12 ms
  • FastSum(lambda): 9 ms

这篇关于总结VS在LINQ性能总和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆