为什么 LINQ .Where(predicate).First() 比 .First(predicate) 快? [英] Why is LINQ .Where(predicate).First() faster than .First(predicate)?

查看:48
本文介绍了为什么 LINQ .Where(predicate).First() 比 .First(predicate) 快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一些性能测试并注意到像

I am doing some performance tests and noticed that a LINQ expression like

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

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

这似乎违反直觉.我原以为第一个表达式会更快,因为只要满足谓词,它就可以停止遍历列表,而我原以为 .Where() 表达式可能会遍历列表在对结果子集调用 .First() 之前的整个列表.即使后者确实短路,它也不应该比直接使用 First 快,但确实如此.

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. Even if the latter does short circuit it should not be faster than using First directly, but it is.

下面是两个非常简单的单元测试来说明这一点.在 TestWhereAndFirst 上进行优化编译时,比 TestFirstOnly 在 .Net 和 Silverlight 4 上快约 30%.我曾尝试使谓词返回更多结果,但性能差异相同.

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.

谁能解释为什么 .First(fn).Where(fn).First() 慢?与 .Where(fn).Count() 相比,我看到了与 .Count(fn) 类似的反直觉结果.

Can any one explain why .First(fn) is slower than .Where(fn).First()? I see a similar counter intuitive result with .Count(fn) compared to .Where(fn).Count().

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);
}

推荐答案

我得到了相同的结果:where+first 比 first 快.

I got the same results: where+first was quicker than first.

正如 Jon 所指出的,Linq 使用惰性求值,因此两种方法的性能应该(并且)大致相似.

As Jon noted, Linq uses lazy evaluation so the performance should be (and is) broadly similar for both methods.

在 Reflector 中,首先使用一个简单的 foreach 循环来遍历集合,但是 Where 有各种专门用于不同集合类型(数组、列表等)的迭代器.大概这就是给 Where 带来微小优势的原因.

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.). Presumably this is what gives Where the small advantage.

这篇关于为什么 LINQ .Where(predicate).First() 比 .First(predicate) 快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆