【发布时间】:2014-10-24 20:17:54
【问题描述】:
我有一个包含两种方法的控制台应用程序:
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比FooA慢10倍以上,而FooB实际上要简单得多(没有调用Intersect()方法)。
这是结果:
00:00:00.0071053 (FooA)
00:00:00.0875303 (FooB)
FooB 可以通过直接返回 source.First() 快很多,反正我使用 ILSpy 反编译了 Distinct 方法并发现完全相同的 foreach 产生返回循环:
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);
【问题讨论】:
-
所以
Intersect永远不会被调用。好点子。我没有考虑到这一点。它没有解释它是否仍然比FooB快很多 -
查看我的答案,差异来自哪里。
标签: c# linq optimization enumerable