C# LINQ 中的聚合与总和性能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11030109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Aggregate vs Sum Performance in LINQ
提问by Gopal
Three different implementations of finding the sum of an IEnumerable < int> sourceare given below along with the time taken when the source has 10,000 integers.
下面给出了查找IEnumerable < int> 源的总和的三种不同实现以及源具有 10,000 个整数时所花费的时间。
source.Aggregate(0, (result, element) => result + element);
takes 3 ms
需要 3 毫秒
source.Sum(c => c);
takes 12 ms
需要 12 毫秒
source.Sum();
takes 1 ms
需要 1 毫秒
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.
我想知道为什么第二个实现比第一个贵四倍。它不应该与第三个实现相同。
采纳答案by svick
Note: My computer is running .Net 4.5 RC, so it's possible that my results are affected by this.
注意:我的电脑运行的是 .Net 4.5 RC,所以我的结果可能会受到影响。
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:
测量只执行一次方法所需的时间通常不是很有用。它很容易被 JIT 编译之类的东西所支配,这些东西在实际代码中并不是真正的瓶颈。因此,我测量了每个方法执行 100 倍(在没有附加调试器的发布模式下)。我的结果是:
Aggregate(): 9 msSum(lambda): 12 msSum(): 6 ms
Aggregate(): 9 毫秒Sum(lambda): 12 毫秒Sum(): 6 毫秒
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:
Sum()最快的事实并不奇怪:它包含一个没有任何委托调用的简单循环,这真的很快。Sum(lambda)和之间的差异Aggregate()并不像你测量的那么明显,但它仍然存在。原因可能是什么?让我们看一下这两种方法的反编译代码:
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.
如您所见,Aggregate()使用了循环但Sum(lambda)使用了Select(),而后者又使用了迭代器。使用迭代器意味着有一些开销:创建迭代器对象和(可能更重要的是)为每个项目再调用一次方法。
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():
让我们Select()通过编写我们自己的Sum(lambda)两次来验证 using实际上是原因,一次 using Select(),其行为应Sum(lambda)与框架中的行为相同,另一次不使用 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(lambda): 12 msFastSum(lambda): 9 ms
SlowSum(lambda): 12 毫秒FastSum(lambda): 9 毫秒

