Aggregate vs Sum Performance in LINQ

aggregate, c#, linq, performance, sum

Solution

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

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:

- `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(lambda)`: 12 ms

- `FastSum(lambda)`: 9 ms

Problem

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); ``` takes 3 ms ``` source.Sum(c => c); ``` takes 12 ms ``` source.Sum(); ``` 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.

Original source