Optimize Enumerable.Range(...).Select(...) by stephentoub · Pull Request #37410 · dotnet/corefx (original) (raw)
Looking at some large code indexes, by far the most common uses of Enumerable.Range are when it's either directly iterated with a foreach, converted to an array with ToArray, or probably the most common, succeeded by Select (and then iterated or ToArray'd). The first two are already decently optimized, with a custom range iterator returned from Enumerable.Range and that iterator already having a ToArray override. But it's missing the Select case. This commit adds that, by copying the existing SelectArrayIterator and then just tweaking it to use _start/_end rather than accessing a stored _source array.
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using System; using System.Collections.Generic; using System.Linq;
[InProcess] [MemoryDiagnoser] public class Test { public static void Main() => BenchmarkRunner.Run();
[Params(1, 10, 100, 1000)]
public int Size { get; set; }
[Benchmark] public void RangeSelectIterate() { foreach (int item in Enumerable.Range(0, Size).Select(i => i)) { } }
[Benchmark] public int[] RangeSelectToArray() => Enumerable.Range(0, Size).Select(i => i).ToArray();
[Benchmark] public List<int> RangeSelectToList() => Enumerable.Range(0, Size).Select(i => i).ToList();
}
Method | Size | Mean Before | Mean After | Memory Before | Memory After |
---|---|---|---|---|---|
RangeSelectIterate | 1 | 83.65 ns | 57.00 ns | 96 B | 88 B |
RangeSelectToArray | 1 | 72.15 ns | 50.64 ns | 128 B | 120 B |
RangeSelectToList | 1 | 77.64 ns | 58.61 ns | 160 B | 152 B |
RangeSelectIterate | 10 | 190.89 ns | 123.68 ns | 96 B | 88 B |
RangeSelectToArray | 10 | 138.11 ns | 71.17 ns | 160 B | 152 B |
RangeSelectToList | 10 | 151.71 ns | 84.80 ns | 192 B | 184 B |
RangeSelectIterate | 100 | 1,136.12 ns | 689.90 ns | 96 B | 88 B |
RangeSelectToArray | 100 | 741.59 ns | 279.15 ns | 520 B | 512 B |
RangeSelectToList | 100 | 727.97 ns | 336.18 ns | 552 B | 544 B |
RangeSelectIterate | 1000 | 10,603.56 ns | 6,362.80 ns | 96 B | 88 B |
RangeSelectToArray | 1000 | 6,729.38 ns | 2,371.04 ns | 4120 B | 4112 B |
RangeSelectToList | 1000 | 6,665.97 ns | 2,799.10 ns | 4152 B | 4144 B |
cc: @maryamariyan, @cston, @danmosemsft