LinqFaster
LinqFaster copied to clipboard
[Question] Span_FirstF and List_FirstF are slower than just calling foreach -> Why?
[Benchmark]
public double IntSpanFirstForEach()
{
Span<int> asSpan = intArray.AsSpan();
foreach (int i in asSpan)
{
if (firstInts(i))
{
return i;
}
}
return 0;
}
[Benchmark]
public double IntSpanFirstFast()
{
return intArray.AsSpan().FirstF(firstInts);
}
[Benchmark]
public double IntListFirstLinq()
{
return intList.First(firstInts);
}
[Benchmark]
public double IntListFirstFast()
{
return intList.FirstF(firstInts);
}
[Benchmark]
public double IntListFirstFast1()
{
Predicate<int> predicate = new Predicate<int>(firstInts);
int sourceCount = intList.Count;
for (int i = 0; i < sourceCount; i++)
{
if (predicate(intList[i]))
{
return intList[i];
}
}
return 0;
}
Just in case the VM is causing problems, this is the host, and it still shows a difference
Ideally it should be in the same region as the ArrayFirstF
result.
try making a local copy of the array inside the function calling FirstF
try making a local copy of the array inside the function calling FirstF
I do not understand, In the Benchmark, or in the Implementation of FirstF
for Span<T>
?
[Benchmark]
public double IntSpanFirstForEach()
{
Span<int> asSpan = intArray.AsSpan();
foreach (int i in asSpan)
{
if (firstInts(i))
{
return i;
}
}
return 0;
}
[Benchmark]
public double IntSpanFirstFast()
{
return intArray.AsSpan().FirstF(firstInts);
}
in the benchmark
in the benchmark
I've shown the code, isn't is generating a local for each of the benchmarks ?
public double IntSpanFirstFast()
{
var localArray = intArray;
return localArray.AsSpan().FirstF(firstInts);
}
No difference ...
[Benchmark]
public double IntSpanFirstForEach()
{
int[] localArray = intArray;
Span<int> asSpan = localArray.AsSpan();
foreach (int i in asSpan)
{
if (firstInts(i))
{
return i;
}
}
return 0;
}
[Benchmark]
public double IntSpanFirstFast()
{
int[] localArray = intArray;
Span<int> asSpan = localArray.AsSpan();
return asSpan.FirstF(firstInts);
}
These are such small differences (nanoseconds) it might just be the function call overhead of calling into FirstF. Like the difference is pretty close to the latency of a single memory location lookup
Because the function is not the same for each run (private static readonly Func<int, bool> firstInts = (x) => x > 0;
) then any difference seen should be taken into account.
Converting to a Span
is quick and does not have a great impact (As seen by the other benchmarks), then these differences should be raising a red flag, especially as the Array.FirstF is so much quicker.
Span is quick, see the difference for Sum, i.e. Span.SumFor is slower than the Span.SumFastF
IntArraySumLinq | 1000000 | 5,610,364.063 ns | 110,617.3880 ns | 178,626.4625 ns | 5,569,376.563 ns | - | - | - | - |
---|---|---|---|---|---|---|---|---|---|
IntArraySumFast | 1000000 | 632,074.231 ns | 11,899.6764 ns | 11,687.0733 ns | 632,253.467 ns | - | - | - | - |
IntSpanSumFor | 1000000 | 959,628.695 ns | 18,512.4370 ns | 24,071.3973 ns | 957,722.656 ns | - | - | - | - |
IntSpanSumFast | 1000000 | 944,971.122 ns | 18,046.1893 ns | 15,997.4767 ns | 941,054.688 ns | - | - | - | - |
Checking back through the Benchmarks... It appears that the Span functions are slower apart from the Sum...
IntArrayAggregateLinq | 1000000 | 6,644,730.651 ns | 72,946.5557 ns | 68,234.2534 ns | 6,645,266.016 ns | - | - | - | - |
---|---|---|---|---|---|---|---|---|---|
IntArrayAggregateFast | 1000000 | 2,155,960.964 ns | 35,396.5436 ns | 33,109.9488 ns | 2,143,233.203 ns | - | - | - | - |
IntReadOnlyArrayAggregateLinq | 1000000 | 7,335,447.578 ns | 74,533.0185 ns | 69,718.2318 ns | 7,309,037.891 ns | - | - | - | 128 B |
IntReadOnlyArrayAggregateFast | 1000000 | 6,347,838.229 ns | 64,908.7109 ns | 60,715.6484 ns | 6,331,896.875 ns | - | - | - | - |
IntSpanAggregateForEach | 1000000 | 2,757,356.406 ns | 39,808.8742 ns | 37,237.2456 ns | 2,745,133.203 ns | - | - | - | - |
IntSpanAggregateFast | 1000000 | 3,085,561.250 ns | 38,936.5386 ns | 36,421.2624 ns | 3,079,746.094 ns | - | - | - | - |
are you testing with .net core? span is slow when not on .net core
Picture states .Net 4.7.2, so nope.
yeah so span being slow is to be expected, nothing to be done about it.
yeah so span being slow is to be expected, nothing to be done about it.
So would it be prudent to move the Linq for Span<T>
into an extensions dll, with a caveat that "Some" API's are not faster ?
#21