c# - 这是异步流程的工作原理吗
问题描述
我是 C# 异步编程的新手,并且已经阅读了几篇关于它的好文章(参见这里、这里和这里的例子)。我想我知道它是如何工作的,但我希望有人能确认我走在正确的轨道上。
如果我理解正确,异步编程是这样工作的:
将关键字 async 添加到一个方法中,以表明它将离开并做自己的事情,而与程序的其余部分正在做什么无关。这基本上就像一个厨师让一个预备厨师去切蘑菇、洋葱和胡萝卜。
async 方法分配给类型为 Task 的任务。Task 是正在运行的方法,或者在我们的例子中是准备厨师。返回类型是任务将返回的类型。一旦分配了任务,当前方法就会忽略它,知道它正在处理。
await 命令是调用方法请求任务结果的地方。继续我们的例子,厨师向预备厨师要切碎的蔬菜。如果Task已经完成,则给出结果,调用方法继续运行。如果任务尚未完成,调用方法必须等待它完成。换句话说,如果在厨师需要蔬菜的时候准备厨师还没有完成切菜,那么厨师必须等待才能继续制作食谱。(我知道,这个比喻在这里不成立,因为真正的厨师会去做其他事情,但这只是为了简化解释。)
要使用 await 命令,方法必须是异步方法。在上面的示例中,调用方法是异步方法。因此,当它遇到 await 命令时,控制会返回到它的调用方法,该方法将继续运行,直到它完成或遇到它自己的 await。
所以,我们现在得到的是方法A调用异步方法B,它调用异步方法C。方法B在await上停止,等待方法C的结果。方法A和C现在都在异步运行,而方法B是等待结果。一旦方法 C 返回结果,然后方法 A 和 B 将异步运行,直到方法 B 完成,或者方法 A 决定它需要等待方法 B 的结果。请注意,方法 B 可能不需要返回结果,因此方法 A 可能在方法 B 之前完成。
这听起来对吗,或者控制从 A 到 B,然后只有在等待被命中时才返回 A?因此,如果 A 没有自己的等待,它将在控制权返回 B 之前完成。
我意识到我在有更多复杂性的地方过于简单化了,但我试图在细节之前理解这些概念。
解决方案
任何时候await
都使用,该方法在该点编译成一个单独的方法,原始方法在该点完成(async
/await
是语法糖)。Task
生成的方法被注册为await
引用的 的延续。如果给定方法中存在多个await
,则相同的过程适用于每个await
.
任何时候async
用来描述一个方法,就意味着该方法支持await
并且可以编译成一系列的延续。该方法的第一部分与调用代码内联调用,但作为 an 的一部分生成的部分await
将排队到 TPL 的默认调度程序(按顺序,随着部分完成)并根据该调度程序的配置方式进行调用。Task
从方法返回的Aasync
将代表整个方法(因此该方法可以在await
方法内的任何位置取消),并且如果/当完成时,注册到该方法的任何延续Task
都将排队到 TPL 的默认调度程序Task
。
在你的类比中,厨师更像是一个线程而不是一个方法。我会使用术语“烹饪动作”来描述方法和延续,如果同时完成任何两个烹饪动作,那是因为厨师已将这些动作委托给副厨师长(另一个线程),除非有没有可用的副厨师长,在这种情况下,厨师以后只能自己做。
异步/等待
public void Main()
{
var result = Calculate(1, 3).Result;
async Task<int> Calculate(int a, int b)
{
var c = await Add(a, 5);
var d = await Add(b, 3);
return await Add(c, d);
}
async Task<int> Add(int a, int b)
{
return a + b;
}
}
纯 TPL
public void Main()
{
const int a = 1;
const int b = 3;
var t1 = Task.Run(() => new
{
c = a + 5
}
);
var t2 = t1.ContinueWith(t =>
new
{
c = t.Result.c,
d = b + 3
}
);
var t3 = t2.ContinueWith(t =>
t.Result.c + t.Result.d
);
var result = t3.Result;
}
推荐阅读
- android - Mapbox 运行时崩溃问题
- intel-xdk - 从哪里可以下载适用于 Mac 的 Intel XDK 版本 3987?
- php - 单击更新按钮时,在 wordpress 中解压缩 zip 文件
- github - 在 GitHub Pages 上将现有存储库添加为页面
- python - 如何在 Python 中输入文件名并下载文件?
- android - KEYBOARD_12KEY、KEYBOARD_QWERTY 和 KEYBOARD_NOKEYS 的 Android 软输入行为
- php - Laravel 中的 $errors 是什么意思
- react-native - 在 RadioGroup 中传递几个值
- android - 如何从房间查询中返回 POJO
- avaya - 如何在主叫方开始时获取有关来电的信息