如何在不使用 await 的情况下发布包装副作用的 ValueTask?

How to release a ValueTask that wraps a side-effect without using await?

提问人:Boris B. 提问时间:11/6/2023 最后编辑:Theodor ZouliasBoris B. 更新时间:11/6/2023 访问量:100

问:

如果我有一个“无结果”的 ValueTask(如普通的 ,而不是 ValueTask<T>)同步完成,则为 true。 尚未编辑。我如何告诉运行时我已经完成了 ,并且如果它恰好由 一个 支持,它可以被重用?ValueTaskvalueTask.IsCompletedSuccessfullyValueTaskawaitValueTaskIValueTaskSource

ValueTask<T>有一个属性,并且访问它(大概)标记为已消耗,但普通没有.ResultValueTask<T>ValueTaskResult

C# 异步 async-await valuetask ivaluetasksource

评论


答:

0赞 Theodor Zoulias 11/6/2023 #1

可以通过调用 来通知基础 IValueTaskSource 对象 ValueTask 已被使用。GetAwaiter() 中。GetResult() 方法:

if (valueTask.IsCompletedSuccessfully)
{
    valueTask.GetAwaiter().GetResult();
}

此调用不会导致任何分配。ValueTaskAwaiter 是一个结构。

对消费的影响没有记录在案。它只能通过研究相关类型(ValueTask、ValueTaskAwaiterManualResetValueTaskSourceCore)的源代码来派生。.GetAwaiter().GetResult()ValueTask

谨慎:在任务完成之前调用 对于 不是有效的操作。此外,禁止多次调用 ,或与任何其他使用操作(如 或 AsTask)同时调用。这些限制记录在结构的“备注”部分中。.GetAwaiter().GetResult()ValueTask.GetAwaiter().GetResult()awaitValueTask

评论

0赞 Boris B. 11/6/2023
GetAwaiter()“为此值创建一个等待者”,根据文档。如果我们已经知道它成功完成,那有必要吗?这难道没有违背 ValueTask 的目的吗?
1赞 Boris B. 11/6/2023
我刚刚花了最后 3 个小时浏览了消息来源,确实你是对的。内部方法 ,这是我需要的,只在 2 个地方公开:编译器生成的 awaiter 和(它只是委托给内部)。然而,直接在 getter 中具有相同的代码,而无需通过 awaiter。两者都在调用,这是实际负责“消耗”任务令牌的原因。ValueTask.ThrowIfCompletedUnsuccessfullyValueTaskAwaiter.GetResult()ValueTask.ThrowIfCompletedUnsuccessfullyValueTask<T>ResultIValueTaskSource.GetResult()
0赞 Charlieface 11/6/2023
你为什么不这样做呢?await
0赞 Boris B. 11/6/2023
@Charlieface因为我需要这个的方法不是.我不得不更改现有方法的实现,并意识到它没有等价物,并想知道如何向最终发出任务已被消耗的信号,因此我提出了我的问题。asyncValueTaskValueTask<T>.ResultIValueTaskSource