2

ValueTask并且ValueTask<TResult>有一个Preserve()方法被概括为“获取一个可以在未来任何时候使用的 ValueTask”。

这是什么意思,我们应该什么时候使用它?这是否意味着ValueTask“在未来的任何时候”都不能使用“正常”?如果是这样,为什么?

4

2 回答 2

3

是对ValueTaska 的性能优化Task,但这种性能是有代价的:你不能像 aValueTask那样自由地使用 a Task。该文档提到了这些限制:

永远不应在ValueTask实例上执行以下操作:

  • 多次等待实例。
  • AsTask多次调用。
  • 使用这些技术中的一种以上来使用实例。

这些限制仅适用于ValueTask由 a 支持的 s IValueTaskSource。AValueTask也可以由 aTaskTResult值(对于 a ValueTask<TResult>)支持。如果您 100% 确定 aValueTask不受 a 支持IValueTaskSource,您可以像 a 一样自由使用它Task。例如你可以await是多次,或者你可以等待它同步完成.GetAwaiter().GetResult()

一般来说,您不知道 aValueTask是如何在内部实现的,即使您知道(通过研究源代码)您也可能不想依赖实现细节。使用该ValueTask.Preserve方法,您可以创建一个新ValueTask的代表原始的ValueTask,并且可以不受限制地使用,因为它不是由IValueTaskSource. 此方法ValueTask仅在由 支持时才会影响IValueTaskSource原始任务,否则它是无操作的(它只是返回未更改的原始任务)。

ValueTask preserved = originalValueTask.Preserve();

调用后Preserve,原ValueTask已消耗。它不应再被等待,或再次 d,或使用该方法Preserve转换为。执行这些操作中的任何一个都可能导致. 但是现在你有了它的表示,它可以像.TaskAsTaskInvalidOperationExceptionpreservedTask


我的回答最初包括一个使用该Preserve方法的实际示例,但事实证明这是不正确的。这个例子可以在这个答案的第 4 版中找到。

于 2022-03-03T22:35:26.407 回答
1

文档不是很清楚。从来源

/// <summary>null if representing a successful synchronous completion, 
/// otherwise a <see cref="Task"/> or a <see cref="IValueTaskSource"/>.</summary>
internal readonly object? _obj;

ValueTask内部声明一个可以为空的容器对象来保存或者Task封装应该是一个IValueTaskSource这样做的。否则,如果相反表示完成。ValueTaskValueTasknullValueTask

public ValueTask Preserve() => _obj == null ? this : new ValueTask(AsTask());

Preserve()如果表示 a或 an (即:) ,则返回一个新的ValueTask表示其基础任务,否则如果表示成功同步完成,则返回自身。这是必要的,因为它是内部的,无法在外部进行测试。ValueTaskTaskIValueTaskSource_obj != nullValueTask_obj

于 2022-03-03T21:10:49.650 回答