Conversation
…n just return the already allocated array
|
Thanks you for your contribution. The code is not performing well with best practices. Instead, just replace the |
|
There may be more unintentional affect after rethinking. Initializing the array pool for each |
|
What would be the typical distribution of the array lengths passed into this API and returned by this API in your case?
This type of change tends to be shifting the cost. It improves the cases that we expect to matter more, and degrades the cases that we expect to be unimportant. My gut-feel is that:
|
Does it make sense to check the length of the incoming array first? I presume that the dotnet runtime will move the unused code paths out of the way, when it is optimizing. |
I can no longer remember the context, but likely less than 4 and almost certainly less than 16 inputted. |
|
@jkotas would the following implementation match what you are suggesting? public static T[] FindAll<T>(T[] array, Predicate<T> match)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
InlineArray4<T> stackAllocatedMatches = default;
Span<T> span = stackAllocatedMatches;
int foundCount = 0;
for (int i = 0; i < array.Length; i++)
{
T value = array[i];
if (match(value))
{
if (foundCount >= span.Length)
{
T[] values = new T[span.Length * 2];
span.CopyTo(values);
span = values;
}
span[foundCount++] = value;
}
}
return span.Slice(0, foundCount).ToArray();
} |
|
Yes, I think something like this would have a better balance of perf characteristics. You do not need to special case Array,Empty in the implementation. Span.ToArray has that special case already. |
|
@Henr1k80 could you please try the implementation #120336 (comment) and get the benchmark numbers for it? Thanks! |
This is a convenience API that is always going to be leaving perf on the table. I do not think it makes sense to overengineer the implementation like this. |
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
|
I just updated the bench results in the original comment to the newest suggestions. |
I found that there were room for improvement in
Array.FindAllNow a small amount of matches are stack allocated and the List is only optionally allocated.
It is always faster with less allocations.
The stack allocated size can be made bigger, but it is fixed size, so it will have a price for no-match schenarios.
InlineArray16<T>is only in .NET 10, but if this should be backported to .NET 8, we can create our local InlineMatchArrayX