将 ValueTask 传播给调用者

问题描述 投票:0回答:1

假设我有一个像这样的方法签名:

public async ValueTask<int> GetSomeValueAsync(int number);

在内部,它可能会进行异步 HTTP 调用,但它会缓存结果,因此下次使用相同的

number
调用它时,它可以从缓存中返回值,而无需异步调用。因此它返回一个
ValueTask
,因为这避免了为同步执行路径创建
Task
的开销。

我的问题是,这个方法的调用者,如果它没有进行其他异步调用,签名应该是

Task
还是应该
ValueTask
一直传播到调用堆栈?

例如应该是这样吗:

public async Task<int> CallingMethodAsync(int number)
{
   return await GetSomeValueAsync(number) + 1;
}

或者应该是:

public async ValueTask<int> CallingMethodAsync(int number)
{
   return await GetSomeValueAsync(number) + 1;
}

(上面的例子经过简化以说明这一点)

c# async-await task valuetask
1个回答
0
投票

假设

GetSomeValueAsync
预计在大多数情况下同步完成,并且
CallingMethodAsync
await
除了
GetSomeValueAsync
之外的任何其他内容,并且您的目标是最小化内存分配,那么
ValueTask<TResult>
更佳。

public async ValueTask<int> CallingMethodAsync(int number)
{
   return await GetSomeValueAsync(number) + 1;
}

这是因为当

ValueTask<TResult>
在创建时已经完成时,它会在内部包装
TResult
,而不是
Task<TResult>
,因此它不会分配任何内容。相反,如果返回
Task<TResult>
,则始终必须创建一个新对象,除非它恰好是 .NET 运行时本身内部缓存的少数类型+值组合之一,例如
Task<int>
值从 -1 到 9(请参阅内部静态
TaskCache
类)。

© www.soinside.com 2019 - 2024. All rights reserved.