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:
Here's a Task<T>
example:
async Task<int> TestTask(int d)
{
await Task.Delay(d);
return 10;
}
Here's the analog ValueTask<T>
example:
Task.Delay
, but often is in many real-world async
/await
scenarios)async ValueTask<int> TestValueTask(int d)
{
await Task.Delay(d);
return 10;
}
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:
class SynchronousFoo<T> : IFoo<T>
{
public ValueTask<T> BarAsync()
{
var value = default(T);
return new ValueTask<T>(value);
}
}
class AsynchronousFoo<T> : IFoo<T>
{
public async ValueTask<T> BarAsync()
{
var value = default(T);
await Task.Delay(1);
return value;
}
}
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