简体   繁体   English

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

[英]Why is LINQ .Where(predicate).First() faster than .First(predicate)?

I am doing some performance tests and noticed that a LINQ expression like 我正在做一些性能测试,发现LINQ表达式像

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

is slower than 比慢

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

This seems counter intuitive. 这似乎与直觉相反。 I would have thought that the first expression would be faster because it can stop iterating over the list as soon as the predicate is satisfied, whereas I would have thought that the .Where() expression might iterate over the whole list before calling .First() on the resulting subset. 我以为第一个表达式会更快,因为一旦满足谓词,它就可以停止迭代列表,而我以为.Where()表达式可能会在调用.First()之前.Where()迭代整个列表.First() Even if the latter does short circuit it should not be faster than using First directly, but it is. 即使后者短路,也不应比直接使用First更快。

Below are two really simple unit tests that illustrate this. 下面是两个非常简单的单元测试,它们说明了这一点。 When compiled with optimisation on TestWhereAndFirst is about 30% faster than TestFirstOnly on .Net and Silverlight 4. I have tried making the predicate return more results but the performance difference is the same. 在.Net和Silverlight 4上使用TestWhereAndFirst进行优化编译时,其速度比TestFirstOnly快30%。我试图使谓词返回更多结果,但是性能差异是相同的。

Can any one explain why .First(fn) is slower than .Where(fn).First() ? 谁能解释为什么.First(fn).Where(fn).First()慢? I see a similar counter intuitive result with .Count(fn) compared to .Where(fn).Count() . .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);
}

I got the same results: where+first was quicker than first. 我得到了相同的结果:where + first比first更快。

As Jon noted, Linq uses lazy evaluation so the performance should be (and is) broadly similar for both methods. 如乔恩(Jon)所述,Linq使用惰性评估,因此两种方法的性能应该(并且应该)大致相似。

Looking in Reflector, First uses a simple foreach loop to iterate through the collection but Where has a variety of iterators specialised for different collection types (arrays, lists, etc.). 在Reflector中看,First使用一个简单的foreach循环来遍历集合,但是Where中有各种专门针对不同集合类型(数组,列表等)的迭代器。 Presumably this is what gives Where the small advantage. 大概这就是给Where带来小的优势的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM