为什么LINQ .Where(谓词).First()比.First(谓词)快?
我正在做一些性能testing,并注意到一个LINQexpression式
result = list.First(f => f.Id == i).Property
比…慢
result = list.Where(f => f.Id == i).First().Property
这似乎是违反直觉的。 我会认为第一个expression式会更快,因为一旦谓词满足,它可以停止迭代列表,而我会认为.Where()
expression式可能会在调用.First()
之前迭代整个列表.First()
在所得到的子集上。 即使后者发生短路,也不应该比直接使用First更快,但它是。
下面是说明这一点的两个非常简单的unit testing。 在TestWhereAndFirst上进行优化编译时,比在.Net和Silverlight 4上的TestFirstOnly快30%左右。我尝试使谓词返回更多的结果,但性能差异是相同的。
任何人都可以解释为什么.First(fn)
慢于.Where(fn).First()
? 我看到类似的计数器直观的结果.Count(fn)
与.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); }
我得到了同样的结果:其中+第一个比第一个更快。
正如Jon指出的那样,Linq使用惰性评估,因此对于这两种方法来说,性能应该(并且)是大致相似的。
看reflection器,首先使用一个简单的foreach循环遍历集合,但Where有各种专用于不同集合types(数组,列表等)的迭代器。 大概这是什么给了那里的小优势。
- 我如何安全地将一个System.Object转换为C#中的`bool`?
- 使用没有Web应用程序的Amazon Elastic Beanstalk部署.NET Windows服务
- 将double转换为int
- 我怎么知道什么监视器的WPF窗口
- 如何从头开始以编程方式configurationlog4net(无configuration)
- ServiceStack.Net Redis:存储相关对象与相关对象ID
- WPF MVVM:如何closures一个窗口
- 在将XML插入SQL Server时如何解决“无法切换编码”错误
- 真的发生了什么{try {return x; } finally {x = null; }声明?