Gop*_*pal 30 c# linq performance aggregate sum
下面给出了三种不同的实现,即查找IEnumerable <int>源的总和,以及源具有10,000个整数所花费的时间.
source.Aggregate(0, (result, element) => result + element);
Run Code Online (Sandbox Code Playgroud)
需要3毫秒
source.Sum(c => c);
Run Code Online (Sandbox Code Playgroud)
需要12毫秒
source.Sum();
Run Code Online (Sandbox Code Playgroud)
需要1毫秒
我想知道为什么第二次实施比第一次实施贵四倍.不应该与第三个实现相同.
svi*_*ick 79
注意:我的计算机正在运行.Net 4.5 RC,因此我的结果可能会受此影响.
测量一次执行方法所花费的时间通常不是很有用.它很容易被像JIT编译这样的东西所支配,而这些东西并不是实际代码中的实际瓶颈.因此,我测量了每个方法执行100×(在没有附带调试器的发布模式下).我的结果是:
Aggregate():9毫秒Sum(lambda):12毫秒Sum():6毫秒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();
}
Run Code Online (Sandbox Code Playgroud)
如您所见,Aggregate()使用循环但Sum(lambda)使用循环Select(),而循环使用迭代器.使用迭代器意味着有一些开销:创建迭代器对象和(可能更重要的是)每个项目的另一个方法调用.
让我们Select()通过编写我们自己的Sum(lambda)两次来验证使用实际上的原因,一次使用Select(),它应该Sum(lambda)与框架相同,并且一次不使用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;
}
Run Code Online (Sandbox Code Playgroud)
我的测量证实了我的想法:
SlowSum(lambda):12毫秒FastSum(lambda):9毫秒