小编典典

为什么要使用任务超过价值任务在 C# 中?

all

从 C# 7.0 开始,异步方法可以返回 ValueTask。解释说当我们有缓存结果或通过同步代码模拟异步时应该使用它。但是,我仍然不明白始终使用
ValueTask 有什么问题,或者实际上为什么 async/await 不是从一开始就使用值类型构建的。ValueTask 什么时候不能完成这项工作?


阅读 102

收藏
2022-05-27

共1个答案

小编典典

API 文档(强调添加):

当方法的操作结果很可能同步可用 并且
期望方法被如此频繁地调用以致Task<TResult>为每次调用分配新的成本将过高时,方法可能会返回此值类型的实例。

使用 aValueTask<TResult>而不是 a需要权衡取舍Task<TResult>。例如,虽然
aValueTask<TResult>可以帮助避免在成功结果同步可用的情况下进行分配,但它也包含两个字段,而Task<TResult>作为引用类型的
a
是单个字段。这意味着方法调用最终会返回两个值得数据的字段,而不是一个需要复制的数据。这也意味着,如果在方法中等待返回其中之一的async方法,则该方法的状态机async将更大,因为需要存储两个字段而不是单个引用的结构。

此外,对于通过使用异步操作的结果以外的用途awaitValueTask<TResult>可能会导致更复杂的编程模型,这反过来实际上会导致更多的分配。例如,考虑一个方法,它可以返回Task<TResult>带有缓存任务的
a 作为公共结果,也可以返回ValueTask<TResult>. 如果结果的使用者想要将其用作 a
Task<TResult>,例如在Task.WhenAlland之类的方法中使用 with
Task.WhenAny,则ValueTask<TResult>首先需要将 the 转换为Task<TResult>using
AsTask,这会导致如果使用了缓存Task<TResult>则可以避免的分配首先。

因此, 任何异步方法的默认选择应该是返回
aTaskTask<TResult>。只有当性能分析证明值得使用时,才应该ValueTask<TResult>使用 a
而不是Task<TResult>.

2022-05-27