ValueTaskT
Task<T>
是一个类,当结果立即可用时,会导致其分配的不必要开销。
ValueTask<T>
是一种结构,并且已被引入以防止在等待时异步操作的结果已经可用的情况下分配 Task
对象。
所以 ValueTask<T>
有两个好处:
1.性能提升
这是一个 Task<T>
示例:
- 需要堆分配
- 使用 JIT 需要 120ns
async Task<int> TestTask(int d)
{
await Task.Delay(d);
return 10;
}
这是模拟 ValueTask<T>
的例子:
- 如果结果是同步已知的,则没有堆分配(在这种情况下由于
Task.Delay
而不是,但通常在许多现实世界的async
/await
场景中) - 使用 JIT 需要 65ns
async ValueTask<int> TestValueTask(int d)
{
await Task.Delay(d);
return 10;
}
2.提高实施灵活性
希望同步的异步接口的实现否则将被迫使用 Task.Run
或 Task.FromResult
(导致上面讨论的性能损失)。因此,对同步实现存在一些压力。
但是使用 ValueTask<T>
,实现可以更自由地在同步或异步之间进行选择,而不会影响调用者。
例如,这是一个带有异步方法的接口:
interface IFoo<T>
{
ValueTask<T> BarAsync();
}
…以下是该方法的调用方式:
IFoo<T> thing = getThing();
var x = await thing.BarAsync();
使用 ValueTask
,上面的代码将适用于同步或异步实现 :
同步实施:
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;
}
}
笔记
虽然计划将 ValueTask
结构添加到 C#7.0 ,但它暂时保留为另一个库。 ValueTask <T> System.Threading.Tasks.Extensions
包可以从 Nuget Gallery 下载