[英]What is the point of ValueTask.Preserve()?
ValueTask
和ValueTask<TResult>
有一个Preserve()
方法,概括为“获取一个可以在未来任何时候使用的 ValueTask”。
那是什么意思,我们什么时候应该使用它? 这是否意味着“在未来的任何时候”都不能使用“正常”的ValueTask
? 如果是这样,为什么?
ValueTask
是对Task
的性能优化,但这种性能是有代价的:您不能像Task
那样自由地使用ValueTask
。 该文档提到了这些限制:
绝不应该在
ValueTask
实例上执行以下操作:
- 多次等待实例。
- 多次调用
AsTask
。- 使用这些技术中的一种以上来使用实例。
这些限制仅适用于由ValueTask
支持的IValueTaskSource
。 ValueTask
也可以由Task
或TResult
值(对于ValueTask<TResult>
)支持。 如果您 100% 确定ValueTask
不受IValueTaskSource
支持,您可以像使用Task
一样自由使用它。 例如,您可以await
多次,或者您可以同步等待它完成.GetAwaiter().GetResult()
。
通常您不知道ValueTask
是如何在内部实现的,即使您知道(通过研究源代码)您也可能不想依赖实现细节。 使用ValueTask.Preserve
方法,您可以创建一个新的ValueTask
来表示原始ValueTask
,并且可以不受限制地使用,因为它不是由IValueTaskSource
烘焙的。 仅当此方法由 IValueTaskSource 支持时,它才会影响原始ValueTask
,否则它是空操作(它只返回未IValueTaskSource
的原始任务)。
ValueTask preserved = originalValueTask.Preserve();
调用Preserve
后,原来的ValueTask
已经被消费了。 不应再等待它,或再次Preserve
d,或使用AsTask
方法将其转换为Task
。 执行任何这些操作都可能导致InvalidOperationException
。 但是现在你有了它的preserved
表示,可以像Task
一样自由使用它。
我的回答最初包括一个使用Preserve
方法的实际例子,但事实证明这是不正确的。 这个例子可以在这个答案的第四次修订中找到。
文档不是很清楚。 从来源:
/// <summary>null if representing a successful synchronous completion,
/// otherwise a <see cref="Task"/> or a <see cref="IValueTaskSource"/>.</summary>
internal readonly object? _obj;
ValueTask
内部声明一个可为空的容器 object 以保存ValueTask
封装的Task
或IValueTaskSource
(如果它是这样做的ValueTask
)。 如果null
代表完成, ValueTask
。
public ValueTask Preserve() => _obj == null ? this : new ValueTask(AsTask());
Preserve()
在ValueTask
表示Task
或IValueTaskSource
(即: _obj != null
)的情况下返回表示其基础任务的新ValueTask
,否则如果ValueTask
表示成功的同步完成,则仅返回其自身。 这是必要的,因为_obj
是内部的,无法在外部进行测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.