Description
When there are more than two Tasks passed to Task.WhenAny, an array is allocated as a protection measure.
|
// Make a defensive copy, as the user may manipulate the input collection |
|
// after we return but before the WhenAny asynchronously completes. |
|
TTask[] tasksCopy = tasks.ToArray(); |
|
foreach (TTask task in tasksCopy) |
Would it be possible to use ArrayPool to eliminate this allocation in WhenAny? This could be beneficial in high-throughput async scenarios where WhenAny is called frequently, as it currently allocates a Task[] on every call with more than two tasks.
I've looked into the internals and it seems like this change could be straightforward to add — the rented array could be returned to the pool once the work is finished.
|
for (int i = 0; i < numTasks; i++) |
|
{ |
|
TTask task = tasks[i]; |
|
if (task != null && // if an element was erroneously nulled out concurrently, just skip it; worst case is we don't remove a continuation |
|
!task.IsCompleted) task.RemoveContinuation(this); |
|
} |
|
_tasks = null; |
I'm happy to implement this change myself if the approach is considered feasible — would just appreciate approval before diving in. It may also be worth adding a dedicated fast path for exactly 3/4 tasks, similar to how 2 tasks is currently handled, to avoid the allocation entirely in that case as well.
Description
When there are more than two Tasks passed to
Task.WhenAny, an array is allocated as a protection measure.runtime/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs
Lines 6637 to 6640 in 6adf63b
Would it be possible to use
ArrayPoolto eliminate this allocation in WhenAny? This could be beneficial in high-throughput async scenarios where WhenAny is called frequently, as it currently allocates a Task[] on every call with more than two tasks.I've looked into the internals and it seems like this change could be straightforward to add — the rented array could be returned to the pool once the work is finished.
runtime/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs
Lines 2319 to 2325 in 6adf63b
I'm happy to implement this change myself if the approach is considered feasible — would just appreciate approval before diving in. It may also be worth adding a dedicated fast path for exactly 3/4 tasks, similar to how 2 tasks is currently handled, to avoid the allocation entirely in that case as well.