Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Implement ValueTask extensibility #16618

Merged
merged 3 commits into from
Mar 1, 2018

Commits on Mar 1, 2018

  1. Implement ValueTask extensibility

    This commit adds support for extending `ValueTask<T>` with arbitrary backing sources.  Prior to this change, `ValueTask<T>` could wrap a `T` or a `Task<T>`; now it can also wrap an `IValueTaskSource<T>`, which can be implemented by arbitrary objects to be represented by `ValueTask<T>`.  These objects can then be pooled and reused to minimize allocation.  The commit also adds a non-generic `ValueTask` that can represent void-returning operations, including a `default` synchronous success, `Task`, and `IValueTaskSource`.  For the non-generic `ValueTask`, the commit also includes awaiters and async method builders, so it can be both awaited and used as the return type of an async method.
    
    The rest of the changes fall into a few buckets all related to enabling this support:
    - Modifying `AsyncTaskMethodBuilder<TResult>.AwaitUnsafeOnCompleted` to specially recognize any `ValueTask` and utilize either the `Task` or `IValueTaskSource` that backs it to avoid allocating an Action MoveNext method.  If every object awaited in an async method is either a `Task`/`Task<T>` or `ValueTask`/`ValueTask<T>`, regardless of what the `ValueTask`/`ValueTask<T>` wraps, we'll be able to avoid allocating the delegate and only allocate the single state machine object that also serves as the returned object.
    - Changing `Stream.WriteAsync` to return `ValueTask` instead of `Task`.  This enables interested overriding stream types to use a reusable/pooled object to avoid `WriteAsync` allocations.
    - Modifying Stream.CopyToAsync to use the new `Memory`-based overloads of `ReadAsync` and `WriteAsync`.  This enables the default `CopyToAsync` implementation to take advantage of any pooling done by derived streams, but even without pooling to take advantage of synchronously completing `ReadAsync`s returning `ValueTask<int>`s that contained an `int` rather than an allocated object. (While I was modifying this, I also removed some unnecessary array clearing that we'd added before later deciding it wasn't needed in general.)
    - Modifying StreamReader/Writer to use the new `ReadAsync`/`WriteAsync` overloads.
    stephentoub committed Mar 1, 2018
    Configuration menu
    Copy the full SHA
    1b81f5b View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    d4e78e8 View commit details
    Browse the repository at this point in the history
  3. Move IValueTaskSource and friends to System.Threading.Tasks.Sources

    Group these more advanced types into a subnamespace.
    stephentoub committed Mar 1, 2018
    Configuration menu
    Copy the full SHA
    f9a312b View commit details
    Browse the repository at this point in the history