为什么LINQ中的Skip()不能优化对象?

时间:2011-06-05 19:06:07

标签: .net linq optimization linq-to-objects

var res = new int[1000000].Skip(999999).First();

如果此查询仅使用索引器而不是遍历999999个条目,那将会很棒。

我查看了System.Core.dll并注意到与Skip()相比,Count()扩展方法已经过优化。如果IEnumerable实现了ICollection,那么它只会调用Count属性。

2 个答案:

答案 0 :(得分:3)

我会让Jon Skeet回答这个问题:

  

如果我们的序列是一个列表,我们可以直接跳到它的右边部分并一次生成一个项目。这听起来不错,但是当我们迭代它时,如果列表改变(或甚至被截断!)会怎样?使用简单迭代器的实现通常会抛出异常,因为更改会使迭代器无效。这绝对是一种行为改变。当我第一次写关于Skip的文章时,我将其作为“可能的”优化包含在内 - 并且实际上在Edulinq源代码中将其打开。我现在认为这是一个错误,并完全删除它。

     

...

     

这两个“优化”的问题可以说是他们在用于延迟执行的迭代器块中应用基于列表的优化。在初始方法调用点或在立即执行运算符(Count,ToList等)中预先优化列表是很好的,因为我们假设序列在方法执行过程中不会改变。我们不能用迭代器块做出这个假设,因为代码流是非常不同的:我们的代码是根据调用者使用MoveNext()重复访问的。

     

https://msmvps.com/blogs/jon_skeet/archive/2011/01/26/reimplementing-linq-to-objects-part-40-optimization.aspx

答案 1 :(得分:3)

如果你看my answer一个类似的问题,似乎应该很容易为任何{{1}提供Skip的非天真(即抛出适当的例外)优化}:

IList

当然,您的示例使用数组。由于数组在迭代期间不会抛出异常,因此即使执行像我的函数那样复杂的操作也是不必要的。因此可以得出结论,MS没有优化它,因为他们没有想到它,或者他们认为这不是一个值得优化的常见案例。