异步编程基础——创建ValueTask
问题
需要实现一个方法,让它返回ValueTask<T>
解决方案
在有同步结果返回、异步操作较为罕见的场景中,可将ValueTask<T>用作一种返回类型。这里也有一条准则,那就是对于自写的应用程序代码,应当使用Task<T>作为返回类型,而不是使用ValueTask<T>.当且仅当使用ValueTask<T>作为返回类型能够提升性能时,才可以考虑使用它。因此,在某些情况下,需要实现一种返回ValueTask<T>的方法。IAsyncDisposable就属于这种情况,它的DisposeAsync方法会返回ValueTask
public async ValueTask<int> MethodAsync()
{
await Task.Delay(100);//异步工作
return 13;
}
很多时候,返回ValueTask<T>的方法也能立刻返回一个值。在这种情况下,以使用ValueTask<T>构造函数优化该场景,然后子需要在必要时发送到缓慢的异步方法中:
public ValueTask<int> MethodAsync()
{
if(CanBehaveSynchronously)
return new ValueTask<int>(13);
return new ValueTask<int>(SlowMethodAsync());
}
private Task<int> SlowMethodAsync();
对非泛型的ValueTask而言,还有个类似的可行办法,此例中的ValueTask默认构造函数用以返回成功完成的ValueTask.下面的例子展示了使用IAsyncDisposable的实现,其中异步丢弃逻辑只运行了一次。在之后的调用中,DisposeAsync方法陈宫且同步地完成。
private Func<Task> _disposeLogic;
public ValueTask DisposeAsync()
{
if(_disposeLogic==null)
return default;
//注意,这个简单的示例对线程而言并不安全
//如果多个线程调用DisposeAsync,那么该逻辑可能不止运行一次
Func<Task>logic=_disposeLogic;
_disposeLogic=null;
return new ValueTask(logic());
}
讨论
大多数方法应当返回Task<T>,这是因为使用Task<T>的陷阱不及使用ValueTask<T>的多。
如果只是使用ValueTask或ValueTask<T>来实现接口,那么可以简单的使用async方法和await方法。只有当你想使用ValueTask<T>时,才会用到更高阶的实现方式。