如果我链接诸如
之类的条款var results = elements
.Where(n => n > 3)
.Where(n => n % 2 == 0);
这比
慢var results = elements.Where(n => n > 3 && n % 2 == 0);
解释原因或原因?
编辑:似乎共识是即使POCO对象迭代两次。如果是这种情况,有人可以解释为什么微软不会合并这些谓词。我偶然发现了Enumerable.CombinePredicates
,我认为这样做了。有人可以解释一下这是做什么的。
答案 0 :(得分:2)
如果你正在谈论LINQ到对象,每个Where
都涉及设置一个新的迭代器状态机,这很昂贵,所以是的,它比将两个条件放在一起要慢。
如果你正在谈论LINQ到别的东西,那么,这取决于;额外的Where
可能只涉及某处额外的字符串连接。它仍然可能更昂贵,但exect差异取决于LINQ提供商。
答案 1 :(得分:2)
修改强>:
我仔细看了一下。 WhereEnumerableIterator
扩展方法返回的Where
实际上会覆盖Where
方法,并将谓词合并为一个回调。
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) {
return new Enumerable.WhereEnumerableIterator<TSource>(
this.source,
Enumerable.CombinePredicates<TSource>(this.predicate, predicate));
}
private static Func<TSource, bool> CombinePredicates<TSource>(
Func<TSource, bool> predicate1, Func<TSource, bool> predicate2
) {
return (TSource x) => predicate1(x) && predicate2(x);
}
因此,我在机器上看到的速度差异应该归因于其他东西。
<击>
第一个示例将循环遍历elements
集合,以查找满足条件item > 3
的项目,并再次查找满足条件item % 2 == 0
的项目。
第二个示例将循环遍历elements
集合,以查找满足条件item > 3 && item % 2 == 0
的项目。
在提供的示例中,第二个很可能总是比第一个快,因为它只会循环elements
一次。
击>
以下是我在我的机器(.NET 3.5)上获得的一些非常一致的结果的示例:
var stopwatch = new System.Diagnostics.Stopwatch();
var elements = Enumerable.Range(1, 100000000);
var results = default(List<int>);
stopwatch.Start();
results = elements.Where(n => n > 3).Where(n => n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
stopwatch.Reset();
stopwatch.Start();
results = elements.Where(n => n > 3 && n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
Console.WriteLine("Done");
Console.ReadLine();
结果:
00:00:03.0932811
00:00:02.3854886
Done
修改强>:
@Rawling是对的,因为我的解释仅适用于POCO对象集合中使用的LINQ。当用作LINQ-to-SQL,NHibernate,EF等的接口时,您的结果将更依赖于实现。