问题
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