异步编程基础——使用ValueTask
问题
需要使用ValueTask<T>值
解决方案
要使用ValueTask<T>值或ValueTask值,最直接、最常见的方法就是使用await。在大多数情况下,只需要这样做:
ValueTask<int> methodAsync();
async Task ConsumingMethodAsync()
{
int value=await MethodAsync();
}
也可以在执行并发操作后执行await,这和Task<T>的用法一样
ValueTask<int> MethodAsync();
async Task ConsumingMethodAsync()
{
ValueTask<int> valueTask=MethodAsync();
...//其他并发工作
int value=await valueTask;
}
对ValueTask或ValueTask<T>只可等待一次
若要进行更为复杂的处理,可以通过调用AsTask把ValueTask<T>转换为Task<T>:
ValueTask<int> MethodAsync();
async Task ConsumingMethodAsync()
{
Task<int> task=MethodAsync().AsTask();
...//其他并发工作
int value=await task;
int anotherValue=await task;
}
对Task<T>多执行await是绝对安全的。通过它也可以实现其他操作,比如异步等待多个操作完成
ValueTask<int> MethodAsync();
async Task ConsumingMethodAsync()
{
Task<int> task1=MethodAsync().AsTask();
Task<int> task2=MethodAsync().AsTask();
int[] results=awaitTask.WhenAll(task1,task2);
}
但是,对于没个ValueTask<T>,只能调用一次AsTask。一种常见的做法是将其即可转换为Task<T>。然后无视ValueTask<T>。不能再同一个ValueTask<T>中对AsTask同时加以await和调用。
大多数的代码硬蛋个要么即可对ValueTask<T>加以await,要么将转换为Task<T>
讨论
ValueTask<T>的其他属性用于更高级的目的,他们的表现方式与那些常见的属性不一样,尤其是ValueTask<T>.Result较之与Task<T>.Result的局限更多。从ValueTask<T>中同步获取结果的代码可能会调用ValueTask<T>.Result或者ValueTask<T>.GetAwaiter().GetResult(),但在ValueTask<T>尚未完成之前,绝不可以调用这些属性。从Task
想从ValueTask或ValueTask<T>中同步于获取结果,只能获取一次,且须在ValueTask完成之后,并且不可对该ValueTask加以await,也不可能将其转换为任务。