微软于2010年10月28日宣布推出了Visual Studio Async CTP,该工具引入了async
和await
关键字,用于在C#/VB中执行异步方法。
起初我认为编译器将这些关键字转换为线程的创建,但根据白皮书和Anders Hejlsberg在PDC演讲(31:00处)中所述,异步操作完全在主线程上进行。
如何在同一线程上并行执行操作?技术上如何实现,并将该功能转换为IL的什么内容?
微软于2010年10月28日宣布推出了Visual Studio Async CTP,该工具引入了async
和await
关键字,用于在C#/VB中执行异步方法。
起初我认为编译器将这些关键字转换为线程的创建,但根据白皮书和Anders Hejlsberg在PDC演讲(31:00处)中所述,异步操作完全在主线程上进行。
如何在同一线程上并行执行操作?技术上如何实现,并将该功能转换为IL的什么内容?
它的工作方式类似于C# 2.0中的yield return
关键字。
异步方法实际上不是普通的顺序方法,而是编译成一个状态机(对象),具有一些状态(本地变量被转换为对象的字段)。在两个await
使用之间的每个代码块都是状态机的一个“步骤”。
这意味着当该方法启动时,它只运行第一步,然后状态机返回并安排执行一些工作-当工作完成时,将运行状态机的下一步。例如,以下代码:
async Task Demo() {
var v1 = foo();
var v2 = await bar();
more(v1, v2);
}
大致翻译为:
class _Demo {
int _v1, _v2;
int _state = 0;
Task<int> _await1;
public void Step() {
switch(this._state) {
case 0:
this._v1 = foo();
this._await1 = bar();
// When the async operation completes, it will call this method
this._state = 1;
op.SetContinuation(Step);
case 1:
this._v2 = this._await1.Result; // Get the result of the operation
more(this._v1, this._v2);
}
}
重要的部分在于它使用了 "SetContinuation" 方法来指定操作完成时应再次调用 "Step" 方法(该方法知道应使用 "_state" 字段运行原始代码的第二部分)。您可以轻松想象 "SetContinuation" 会是类似于 "btn.Click += Step" 的东西,这将完全在单个线程上运行。如何在同一线程上并行执行操作?
你无法这样做。异步不是“并行”或“并发”。异步可能会使用并行方式实现,也可能不会。它可能通过将工作分解为小块,将每个工作块放入队列中,然后在线程没有执行其他任务时执行每个工作块来实现。
我在我的博客上写了一系列关于所有这些内容如何运作的文章;直接与此问题相关的文章可能会在下周四发布。请访问此链接获取详细信息。
async
和await
关键字的作用是,每当一个async
方法使用await
关键字时,编译器将把该方法的余下部分转换为一个继续执行的程序,并在异步操作完成时进行调度。这使得async
方法可以立即返回给调用者,并在异步部分完成后恢复工作。