-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
With Linq-to-Objects it is quite common practice to perform a series of transformations, and then materialize sequence to a concrete collection type by calling ToArray(), ToList(), ToDictionary(). These operations would work much faster if they knew the number of elements in the sequence.
Currently System.Linq.Enumerable has special treatment for ICollection interface only.
I suppose that additional support for IReadOnlyCollection can improve performance in some cases, because through it we can figure out the total number of elements.
Another problem with System.Linq is that in many cases the information about the number of elements is lost. One of the most common example:
List<int> source = ...;
List<int> transformed = source.Select(o => o + 1).ToList();Obviously Select does not change the number of elements in the sequence, but ToList method cannot take advantage of that. Information is lost.
In this particular scenario, it would be great for Select to return some SelectIterator instance, which implements IReadOnlyCollection, and thereby passes the number of elements to the subsequent methods.
Steps to measure performance gain:
- Find in System.Linq.Tests\Performance the test for the method you've changed;
- Uncomment
[Fact]attribute above that method; - Build test project by Visual Studio in Release mode;
- Go to the folder with tests binaries:
bin\tests\Windows_NT.AnyCPU.Release\System.Linq.Tests\aspnetcore50\; - Open command prompt (cmd.exe or PowerShell);
- Run command:
CoreRun.exe xunit.console.netcore.exe System.Linq.Tests.dll -parallel none -trait "Perf=true"; - Wait for results that will be printed right in the command window;
- Don't forget to run tests with different collection sizes. This can be done by varying elementCount argument of Measure method.
Casting to IReadOnlyCollection<T> is a slow operation so it is not a good idea to check if this interface implemented. The performance drop will be most noticeable on the small collections.
Tasks:
-
Select: add iterators forList<T>,Array[T],ICollection<T>; -
ToArray,ToDictionary: add special support forICollection<T>(and, very carefully, forIReadOnlyCollection<T>) to get the initial capacity; -
ToList(???): add special support forIReadOnlyCollection<T>to get the initial capacity (separated as it will affect System.Collections.Generic); -
OrderBy(Descending)/ThanBy(Descending): implement special iterator forICollection<T>to propagateCount; -
Cast,Reverse: add iterators forICollection<T>to propagateCount; -
Range,Repeat: add an iterator that implementsICollection<T>; -
Skip,Take: add an iterator that handleICollection<T>; - Add performance tests for System.Linq