C# 等待已完成的任务时会发生什么情况?

C# 等待已完成的任务时会发生什么情况?,c#,.net,asynchronous,async-await,C#,.net,Asynchronous,Async Await,当我构造一个我拥有的类的实例时,我想触发一个令牌更新函数(async方法),并让它在后台运行(我保留对返回的任务的引用) 稍后,当用户触发请求时,我希望等待任务 让我们假设任务在1秒后完成,用户在2秒后触发请求(这意味着任务完成) 处理用户请求的方法waitsTask,它会立即得到值吗?毕竟,任务已经完成并保存了该值。您将直接输入结果。任务完成后,其result属性将包含结果并保留它 处理用户请求的方法等待该任务,它会立即得到值吗 对。你可以认为它是懒惰的,如果你等待一个已经完成的任务,它会立即

当我构造一个我拥有的类的实例时,我想触发一个令牌更新函数(
async
方法),并让它在后台运行(我保留对返回的
任务的引用)

稍后,当用户触发请求时,我希望等待
任务

让我们假设
任务
在1秒后完成,用户在2秒后触发请求(这意味着
任务
完成)


处理用户请求的方法
wait
s
Task
,它会立即得到值吗?毕竟,
任务
已经完成并保存了该值。

您将直接输入结果。任务完成后,其result属性将包含结果并保留它

处理用户请求的方法等待该任务,它会立即得到值吗

对。你可以认为它是懒惰的,如果你等待一个已经完成的任务,它会立即返回。您可以在不同的线程上等待它几次,它只有在得到结果(或出现故障)后才会返回


正是因为这个原因,才添加了一个细节。您可以
等待
此操作,它将立即返回已完成的成功任务。

您可以使用task创建已完成的任务。FromResult(value)并等待:

var result = await Task.FromResult(5);
Debug.Assert(result == 5);
例如,如果您有一个方法可以返回缓存数据,但第一次需要异步获取数据,那么这将非常有用


因此,是的,您可以等待已经完成的任务。

虽然OP没有提到
ValueTask
,但我添加此答案以包括
ValueTask
,因为它是在最初提出此问题后添加的

  • 关于
    任务
    任务
    ,正如其他人所指出的,您可以 多次等待
    任务
    (或完成
    任务
    )。如果任务已完成 运行到完成,它会立即返回
  • 但是,如果您正在使用
    ValueTask
    ValueTask
    ,则不能再等待了 不止一次
    ValueTask
    ValueTask
    是在.NET中引入的 Core 2.0和用于避免/最小化性能敏感区域的内存分配
正如Stephen Toub在Dotnet博客上所说:

但是,因为ValueTask和ValueTask可能包装为可重用的 对象上,实际上存在显著的约束 当与任务和任务进行比较时,是否有人 偏离只等待他们的理想路径。总的来说 绝对不能对ValueTask执行以下操作/ ValueTask:

  • 多次等待ValueTask/ValueTask。这个 基础对象可能已被回收,并已被使用 另一个手术。相反,一项任务/任务永远不会 从完整状态过渡到不完整状态,因此您可以等待 根据需要多次,每次都会得到相同的答案 时间
  • 同时等待ValueTask/ValueTask。这个 基础对象希望只使用来自 一次只有一个消费者,并试图同时等待它 很容易引入竞争条件和微妙的程序错误。它是 也只是上述不良操作的一个更具体的例子:“等待 ValueTask/ValueTask多次。”相比之下,任务/ 任务不支持任意数量的并发等待
  • 使用 .GetAwaiter().GetResult()当操作尚未完成时。这个 IValueTaskSource/IValueTaskSource实施不需要 支持阻塞,直到操作完成,可能不会,所以 这种操作本质上是一种竞争条件,不太可能 按来电者的意愿行事。相比之下,任务/任务 请启用此选项,在任务完成之前阻止调用方
如果您有ValueTask或ValueTask,并且需要执行以下操作之一: 这些东西,您应该使用.AsTask()来获取任务 然后对生成的任务对象进行操作。在那之后,你 不应再与该ValueTask/ValueTask交互

简短的规则是:对于ValueTask或ValueTask,您 应该直接等待它(可以选择使用 .ConfigureAwait(false))或直接对其调用AsTask(),然后 不要再使用它,例如

以及来自
ValueTask
ValueTask
的MSDN文档:

以下操作不应在机器上执行 ValueTask实例:

  • 多次等待该实例
  • 多次调用AsTask
  • 在操作尚未完成时使用.Result或.GetAwaiter().GetResult(),或多次使用它们
  • 使用这些技术中的多个来使用实例
如果执行上述任一操作,则结果未定义。


您可以阅读更多关于
ValueTask
ValueTask
和的信息。

是的,它会立即返回结果。@MatthewWatson为什么不写它作为答案?我本来会接受你的答案的。我想,它实际上不够长或不够详细,不足以作为答案来写。请注意,如果你多次调用
wait
,它将每次返回它,如果它不是值,它将通过引用返回它。我不确定实际任务是否100%相同,但我会这样假设。