为什么 LINQ. Where (谓词) . First()比. First (谓词)快?

我正在做一些性能测试,并注意到一个 LINQ 表达式像

result = list.First(f => f.Id == i).Property

慢于

result = list.Where(f => f.Id == i).First().Property

这似乎有悖常理。我认为第一个表达式会更快,因为一旦满足谓词,它就可以停止对列表的迭代,而我认为 .Where()表达式可以在对结果子集调用 .First()之前对整个列表进行迭代。即使后者做短路,它不应该比直接使用第一快,但它是。

下面两个非常简单的单元测试说明了这一点。如果使用 TestWherAndFirst 进行优化编译,比 TestFirstOnly 快30% 左右。Net 和 Silverlight 4。我尝试使谓词返回更多的结果,但性能差异是相同的。

有人能解释为什么 .First(fn).Where(fn).First()慢吗?与 .Where(fn).Count()相比,我看到了与 .Count(fn)类似的计数器直观结果。

private const int Range = 50000;


private class Simple
{
public int Id { get; set; }
public int Value { get; set; }
}


[TestMethod()]
public void TestFirstOnly()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}


int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.First(f => f.Id == i).Value;
}


Assert.IsTrue(result > 0);
}


[TestMethod()]
public void TestWhereAndFirst()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}


int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.Where(f => f.Id == i).First().Value;
}


Assert.IsTrue(result > 0);
}
30840 次浏览

我得到了同样的结果: where + first 比 first 更快。

正如 Jon 指出的,Linq 使用延迟计算,因此两种方法的性能应该(而且是)大致相似。

查看 Refector,First 使用一个简单的 foreach 循环来迭代集合,但 Where 有各种专门用于不同集合类型(数组、列表等)的迭代器。大概这就是 Where 的小优势。