从 C# 7.0 开始,异步方法可以返回 ValueTask
ValueTask<T>
的好处(在分配方面)没有实现实际上异步操作(因为在这种情况下 ValueTask<T>
仍需要堆分配)有关。还有 Task<T>
在库中有很多其他支持的问题。
从 the API docs(强调添加):
方法可能会返回此值类型的实例,因为它们的操作结果可能会同步可用,并且当方法被期望如此频繁地调用以致于为每次调用分配新的 Task
但是我仍然不明白总是使用 ValueTask 有什么问题
结构类型不是免费的。复制大于引用大小的结构可能比复制引用要慢。存储大于引用的结构比存储引用占用更多的内存。当可以注册引用时,可能不会注册大于 64 位的结构。降低收集压力的好处可能不会超过成本。
性能问题应该通过工程学科来解决。制定目标,根据目标衡量您的进度,然后决定在目标未实现时如何修改程序,并在此过程中进行衡量以确保您的更改实际上是改进。
为什么 async/await 从一开始就没有使用值类型构建。
在 Task<T>
类型已经存在很久之后,await
才被添加到 C#。在已经存在一种新类型的情况下发明一种新类型会有些不合常理。 await
在确定 2012 年推出的那款之前,经历了许多设计迭代。完美是优秀的敌人;最好发布一个与现有基础架构配合良好的解决方案,然后如果有用户需求,稍后再提供改进。
我还注意到,允许用户提供的类型作为编译器生成方法的输出的新特性增加了相当大的风险和测试负担。当您唯一可以返回的东西是 void 或任务时,测试团队不必考虑返回某些绝对疯狂的类型的任何场景。测试编译器意味着不仅要弄清楚人们可能编写什么程序,还要弄清楚什么程序是可能编写的,因为我们希望编译器能够编译所有合法程序,而不仅仅是所有合理的程序。这太贵了。
有人可以解释 ValueTask 何时无法完成这项工作吗?
事情的目的是提高性能。如果它不能显着地提高性能,它就无法完成这项工作。不能保证它会。
Structs that are larger than 64 bits might not be enregistered when a reference could be enregistered
...如果其他人想知道,这里的“注册”一词可能是指“存储在 CPU 寄存器中”(这是可用的最快内存位置)。
有一些changes in .Net Core 2.1。从 .net core 2.1 开始,ValueTask 不仅可以表示同步完成的动作,还可以表示异步完成。此外,我们收到非泛型 ValueTask
类型。
我将离开与您的问题相关的 Stephen Toub comment:
我们仍然需要正式的指导,但我希望公共 API 表面区域会是这样的:任务提供了最大的可用性。 ValueTask 提供了最多的性能优化选项。如果您正在编写其他人将覆盖的接口/虚拟方法,那么 ValueTask 是正确的默认选择。如果您希望 API 用于分配很重要的热路径,那么 ValueTask 是一个不错的选择。否则,在性能不重要的情况下,默认为 Task,因为它提供了更好的保证和可用性。从实现的角度来看,许多返回的 ValueTask 实例仍将由 Task 支持。
功能不仅可以在 .net core 2.1 中使用。您将能够将它与 System.Threading.Tasks.Extensions 包一起使用。
来自 Marc 的最新信息(2019 年 8 月)
当某事通常或总是将是真正异步的,即不是立即完成时,使用 Task;当某些事情通常或总是要同步时使用 ValueTask,即值将是内联已知的;还可以在无法知道答案的多态场景(虚拟、接口)中使用 ValueTask。
来源:https://blog.marcgravell.com/2019/08/prefer-valuetask-to-task-always-and.html
当我有类似的问题时,我按照上面的博客文章进行了最近的一个项目。
Task
分配(如今它既小又便宜),但代价是使 调用者的 现有分配更大并且返回值的大小加倍(影响寄存器分配)。虽然它是缓冲读取场景的明确选择,但我不建议将其默认应用于所有接口。Task
或ValueTask
都可以用作同步返回类型(使用Task.FromResult
)。但是,如果您有一些您期望同步的东西,那么ValueTask
中仍有价值(呵呵)。ReadByteAsync
是一个典型的例子。我相信ValueTask
主要是为新的“通道”(低级字节流)创建的,可能也用于性能真正重要的 ASP.NET 核心。Task<T>
作为默认值。这只是因为大多数开发人员不熟悉ValueTask<T>
周围的限制(特别是“仅消费一次”规则和“无阻塞”规则)。也就是说,如果您团队中的所有开发人员都对ValueTask<T>
感到满意,那么我会推荐一个 团队级别 的指南,即首选ValueTask<T>
。