Reduce pipe read allocations due to async state and context capturing #11935
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Changes
CommunicationsUtils.ReadAsync
to avoid redundant state machine allocations.ConfigureAwait(false)
to awaited reads (implicit withTask.Result
) to reduce allocations due to context capturing.Task
whenReadAsync()
completes synchronously and returns aValueTask
.Context
Currently the pipe read loops on .NET Core go through a helper in
CommunicationsUtilities
that looks like this:Unfortunately when used within an outer loop, this leads to a ton of extra allocations due to having to create a new
AsyncStateMachineBox
for every iteration.Here's an example:
Using
NodeProviderOutOfProcBase.ReadPacketLoopAsync()
as an example - after this change, we only see the single state machine allocations for the outer loop (1 per pipe client) as it's reused, even when the async method schedules a continuation:Profiles
Here's two profiles comparing total before / after on a .NET Core build (see objects allocated, total allocations, GC). This is accounting for ~8% of allocations on the main node.