У меня есть консольное приложение, которое содержит два метода:Почему этот метод расширения IEnumerable намного медленнее, чем другой (более простой) метод расширения (который только повторяет ввод)?
public static IEnumerable<TSource>
FooA<TSource>(this IEnumerable<IEnumerable<TSource>> source)
{
return source.Aggregate((x, y) => x.Intersect(y));
}
public static IEnumerable<TSource>
FooB<TSource>(this IEnumerable<IEnumerable<TSource>> source)
{
foreach (TSource element in source.First())
{
yield return element;
}
}
Что она делает: как взять последовательность последовательностей, FooA
производят пересечение множества всех из них, а затем возвращать результат. FooB
просто повторите первую последовательность.
То, что я не понимаю: FooB
более чем в 10 раз медленнее, чем FooA
, в то время как FooB
на самом деле гораздо более простой (не вызов Intersect()
метода).
Вот результаты:
00:00:00.0071053 (FooA)
00:00:00.0875303 (FooB)
FooB
может быть намного быстрее, возвращаясь непосредственно source.First()
, во всяком случае я декомпилирован Distinct
метода с использованием ILSpy и нашел точно такую же цикл Еогеасп обратного выхода:
private static IEnumerable<TSource> DistinctIterator<TSource>
(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource current in source)
{
if (set.Add(current))
{
yield return current;
}
}
yield break;
}
Также : в коде я использую я не могу вернуть source.First()
(я получаю CS1622). То, что я показываю здесь, на самом деле гораздо более простой код, который я урезал для отладки.
Вот код я использую для тестирования:
List<List<int>> foo = new List<List<int>>();
foo.Add(new List<int>(Enumerable.Range(0, 3000*1000)));
Stopwatch sa = new Stopwatch();
sa.Start();
List<int> la = FooA(foo).ToList();
Console.WriteLine(sa.Elapsed);
Stopwatch sb = new Stopwatch();
sb.Start();
List<int> lb = FooB(foo).ToList();
Console.WriteLine(sb.Elapsed);
Так что «Интерсект» никогда не называется. Хорошая точка зрения. Я об этом не думал. Он не объясняет, будет ли он все же намного быстрее, чем 'FooB', однако – tigrou
См. Мой ответ, где разница. –