Linq的Skip和Take是否针对阵列进行了优化? [4.0版]

时间:2014-11-01 00:45:11

标签: c# .net arrays linq .net-4.0

从数组中复制范围是一种常见情况。 C#以各种方式支持此操作,例如使用Array.Copy,也可以使用Linq的Skip and Take组合。

从.NET 4.0开始,Skip和Take操作是否仍会增加相当大的开销,或者他们是否认识(在编译时或运行时)他们的目标是一个数组?

澄清:我指的是a)跳过初始字节所花费的时间,以及b)Skip-Take-ToArray的组合,它没有副作用。例如,new byte[10000].Skip(9999).Take(1).ToArray() 可以以这种方式优化,并且(对于大n)明显更快。

3 个答案:

答案 0 :(得分:3)

Skip / Take仍然在O(n)中运行,因为LINQ必须保持知道如何更改数组中的元素以及对象如何保持对变化的了解。因此,在优化O(同时) 1)似乎微不足道,目前尚未实现。

请参阅:https://edulinq.googlecode.com/hg/posts/40-Optimization.html

Jon Skeet几年前有一篇很棒的博客,在“重新实现LINQ”(http://codeblog.jonskeet.uk/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile/)中讨论了这些以及更多内容。这是一个很好的阅读。

答案 1 :(得分:2)

由于它们未在4.5中进行优化,我可以自信地说它们未在4.0中进行优化

http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs#83ec6a20321060a1#references

顺便说一句,即使在阵列上,也没有办法取得O(1),因为它的输出为N(假设它当然是迭代的)

答案 2 :(得分:2)

最好的优化是,如果在Skip(k)上,第一个.MoveNext只将内部索引设置为k,我认为JITter可以执行此操作,但似乎不是,对于我试过的版本。

要优化的代码是:

while (count > 0 && e.MoveNext()) count--;

来自SkipIterator和:

      public bool MoveNext() {
            if (_index < _endIndex) {
                _index++;
                return (_index < _endIndex);
            }
            return false;
        }

来自SZGenericArrayEnumerator

(参考源是4.5.1,但反射器在4.0中显示非常相似的代码。)