Are Linq's Skip and Take optimized for arrays? [4.0 edition]

时光怂恿深爱的人放手 提交于 2019-12-10 15:59:45

问题


It's a common situation to copy a range from an array. C# supports this operation in various ways, for instance using Array.Copy, but also by Linq's Skip and Take combination.

Starting at .NET 4.0, do the Skip and Take operations still add considerable overhead, or do they recognize (either at compile time or at run time) their target is an array?

To clarify: I am referring to a) the time taken to skip the initial bytes and b) to the combination of Skip-Take-ToArray, which does not suffer from side effects. For instance, new byte[10000].Skip(9999).Take(1).ToArray() could be optimized this way and would (for large n) be noticeably faster.


回答1:


Skip/Take still operate in O(n) due to how LINQ has to maintain knowledge of how elements even in arrays can be changed and how the objects have to stay aware of the changes.Therefore, while the optimizations to O(1) seems trivial, it is not currently realized.

See: https://edulinq.googlecode.com/hg/posts/40-Optimization.html

Jon Skeet had an excellent blog a few years back discussing these and more in "reimplementing LINQ" (http://codeblog.jonskeet.uk/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile/). It's a great read.




回答2:


Since they are not optimized in 4.5 I can confidently say that they are not optimized in 4.0 either

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

BTW there is no way Take is O(1) even on arrays since it has an output of N (assuming it is iterated of course)




回答3:


The optimisation that would be nice is if on Skip(k) the first .MoveNext just sets the internal index to k, and I thought the JITter could do this, but it seems not to, for the versions I've tried.

The code to be optimised is:

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

from SkipIterator and:

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

from SZGenericArrayEnumerator.

(The reference source is 4.5.1, but reflector shows very similar code in 4.0.)



来源:https://stackoverflow.com/questions/26685234/are-linqs-skip-and-take-optimized-for-arrays-4-0-edition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!