-
Notifications
You must be signed in to change notification settings - Fork 16k
Description
I would like to implement support for async/await versions of all methods dealing with I/O.
Rationale
Mixing async and sync code in C# is very inefective thread-wise. It is a good practise to have entire code top-down async, but the worst case-scenario is when synchronous code calls async code like in case of Stream.Read and Stream.Write.
Today the only way to efficiently use protobuf in async code is to copy buffers to the memory and then perform deserialization synchronously. What makes it virtually impossible to use protobuf in streaming scenarios with near-to-constant memory.
Background
Lately there have been many improvements to the TPL to allow more efficient (allocation-wise) handling of many scenarious especially parser-like where most of methods return synchronously. ValueTask and Task.CompletedTask are the most important of those improvements.
High-level plan
- Duplicate all I/O-bound methods in the following manner:
ReturnType MethodName(Arguments)
to
async ValueTask MethodNameAsync(Arguments, CancellationToken cancellationToken)
void MethodName(Arguments)
to
async Task MethodNameAsync(Arguments, CancellationToken cancellationToken)
And all references in async methods to those methods with await CalledMethodAsync(..., cancellationToken)
This way we have perfectly correct implementation (but not optimal, especially allocation-wise).
Replace all calls to Stream.Read/Write with proper ReadAsync/WriteAsync
-
After testing this version start optimizations:
a. Remove constructs like async await = where possible
b. Try to use as much of ValueTask and Task.CompletedTask as possible.
c. Try to inline some async calls to avoid generation of separate state-machines -
Modify code-generator to generate async variants.
I would be happy to create PR for this proposal.
However I believe optimization will be a bit longer process, going far beyond this single PR.