Ответ 1
Примечание. Мой компьютер работает .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();
}
Как вы можете видеть, 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;
}
Мои измерения подтверждают, что я думал:
-
SlowSum(lambda)
: 12 мс -
FastSum(lambda)
: 9 мс