.NET Core下的Task<TResult>是如何用异步方法构造的

问题描述 投票:0回答:1

读完这篇非常深入的博客文章后,我仍然无法理解

Task<TResult>
在从异步方法返回之前是如何真正构造的。

我了解了编译方法如何首次初始化并运行状态机。然后,如果第一个等待尚未完成,它将为其注册一个延续到当前正在运行的

MoveNext()
方法,然后从该方法返回到已编译的方法。 此时编译后的方法返回
builder.Task<TResult>

通过浏览源代码,我了解了它背后的一些魔力,即它是派生任务的实例

AsyncStateMachineBox<TStateMachine>
,但我不明白这个任务在第一次构造时代表什么。

这是我们刚刚注册的第一个要等待的延续吗?但是如果还有其他等待需要自己的延续任务怎么办?

c# async-await
1个回答
0
投票

感谢评论(尤其是 Marc Gravell)以及这个 随附视频对最初引用的博客文章的提示(例如,使用任务的异步操作的逻辑分为两种类型

Task<TResult>
(消费者)和
 TaskCompletionSource<TResult>
(生产者)遵循生产者-消费者模式),我想我可以回答我自己的问题(欢迎任何评论)。

来自TaskCompletionSource<TResult>

源代码
中的注释:

它可以创建可以分发给消费者的任务, 这些消费者可以像使用任何任务一样使用任务的成员 其他。然而,与大多数任务不同,由 a 创建的任务的状态 TaskCompletionSource 由以下方法显式控制 任务完成源。这使得外部的完成 要传播到底层任务的异步操作。这 分离还确保消费者无法过渡 无法访问相应的 TaskCompletionSource 的状态。

但是,C# 编译器不使用

TaskCompletionSource<TResult>
而是使用
AsyncTaskMethodBuilder<TResult>
来实现此模式。 他们所做的事情非常相似,具有诸如

之类的方法
public void SetResult(TResult result)

public void SetException(Exception exception)

如果要反编译从异步方法生成的状态机,则

MoveNext()
方法的末尾会利用这些。

catch (Exception exception)
{
    <>1__state = -2;
    <>t__builder.SetException(exception);
    return;
}
<>1__state = -2;
<>t__builder.SetResult();

如果我们出于某种原因决定对从异步方法收到的任务进行

Wait()
,这些方法会执行实际的信号发送/解除阻塞。

回答我原来的问题

但我不明白这个任务第一次时代表什么 已建成。

AsyncTaskMethodBuilder<TResult>
类型为异步方法创建一个全新的
Task<TResult>
(作为
a derived type AsyncStateMachineBox<TStateMachine>
实例,这主要是为了优化/堆栈与堆的考虑)。

这是我们刚刚注册的延续吗? 敬畏吗?但是如果还有其他需要自己的等待怎么办 继续任务?

不。我们将状态机的 MoveNext() 回调注册为我们等待的每个异步操作的延续。一旦所有异步操作完成,并且到达状态机

MoveNext
() 代码的末尾,我们调用 SetResult 或 SetException 来完成我们构建的任务,以跟踪整个操作的成功。该任务不会在中间步骤(即每个检查点之后)更新。它仅代表最终结果。

© www.soinside.com 2019 - 2024. All rights reserved.