C# Language ValueTask


Example

Task<T> is a class and causes the unnecessary overhead of its allocation when the result is immediately available.

ValueTask<T> is a structure and has been introduced to prevent the allocation of a Task object in case the result of the async operation is already available at the time of awaiting.

So ValueTask<T> provides two benefits:

1. Performance increase

Here's a Task<T> example:

  • Requires heap allocation
  • Takes 120ns with JIT
async Task<int> TestTask(int d)
{
    await Task.Delay(d);
    return 10;
}

Here's the analog ValueTask<T> example:

  • No heap allocation if the result is known synchronously (which it is not in this case because of the Task.Delay, but often is in many real-world async/await scenarios)
  • Takes 65ns with JIT
async ValueTask<int> TestValueTask(int d)
{
    await Task.Delay(d);
    return 10;
}

2. Increased implementation flexibility

Implementations of an async interface wishing to be synchronous would otherwise be forced to use either Task.Run or Task.FromResult (resulting in the performance penalty discussed above). Thus there's some pressure against synchronous implementations.

But with ValueTask<T>, implementations are more free to choose between being synchronous or asynchronous without impacting callers.

For example, here's an interface with an asynchronous method:

interface IFoo<T>
{
    ValueTask<T> BarAsync();
}

...and here's how that method might be called:

IFoo<T> thing = getThing();
var x = await thing.BarAsync();

With ValueTask, the above code will work with either synchronous or asynchronous implementations:

Synchronous implementation:

class SynchronousFoo<T> : IFoo<T>
{
    public ValueTask<T> BarAsync()
    {
        var value = default(T);
        return new ValueTask<T>(value);
    }
}

Asynchronous implementation

class AsynchronousFoo<T> : IFoo<T>
{
    public async ValueTask<T> BarAsync()
    {
        var value = default(T);
        await Task.Delay(1);
        return value;
    }
}

Notes

Although ValueTask struct was being planned to be added to C# 7.0, it has been kept as another library for the time being. ValueTask<T> System.Threading.Tasks.Extensions package can be downloaded from Nuget Gallery