Uwaga: Mój komputer działa .Net 4.5 RC, więc możliwe, że wpłyną na to moje wyniki.
Mierzenie czasu potrzebnego do wykonania metody tylko raz jest zazwyczaj mało przydatne. Może być łatwo zdominowany przez takie rzeczy jak kompilacja JIT, które nie są prawdziwymi wąskimi gardłami w prawdziwym kodzie. Z tego powodu zmierzyłem wykonanie każdej metody 100 × (w trybie Release bez dołączonego debuggera). Moje wyniki to:
Aggregate()
: 9 ms
Sum(lambda)
: 12 ms
Sum()
: 6 ms
Fakt Sum()
jest najszybszym nie dziwi: zawiera prostą pętlę bez wywoływania delegatów, co jest naprawdę szybkie. Różnica między wartościami Sum(lambda)
i Aggregate()
nie jest tak znacząca, jak mierzono, ale wciąż jest. Jaki mógł być tego powód? Spójrzmy na kod decompiled dla dwóch metod:
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();
}
Jak widać, Aggregate()
wykorzystuje pętlę ale Sum(lambda)
wykorzystuje Select()
, który z kolei używa iterator. I używanie iteratora oznacza pewne obciążenie: tworzenie obiektu iteratora i (prawdopodobnie ważniejsze) jeszcze jedno wywołanie metody dla każdego elementu.
Chodźmy sprawdzić, używając Select()
jest rzeczywiście powodem pisząc własny Sum(lambda)
dwa razy, raz za pomocą Select()
, który powinien zachowywać się tak samo jak Sum(lambda)
z ram, a raz bez użycia 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;
}
Moje pomiary potwierdzają to, co pomyślałem:
SlowSum(lambda)
: 12 ms
FastSum(lambda)
: 9 ms
Jakie są twoje warunki testu? –
jak się masz te czasy? Ile czasu wypróbowałeś wyniki? –
Profilowałem go za pomocą dotTrace. Uruchomiłem go raz, ale trzy przebiegi są niezależne. – Gopal