Microsoft今天(2010 年 10 月 28 日)宣布了Visual Studio Async CTPasync
,它在 C#/VB 中引入了andawait
关键字,用于异步方法执行。
首先,我认为编译器会将关键字转换为线程的创建,但根据白皮书和 Anders Hejlsberg 的PDC 演示文稿(31:00),异步操作完全发生在主线程上。
如何在同一线程上并行执行操作?它在技术上是如何实现的,以及在 IL 中实际翻译的功能是什么?
Microsoft今天(2010 年 10 月 28 日)宣布了Visual Studio Async CTPasync
,它在 C#/VB 中引入了andawait
关键字,用于异步方法执行。
首先,我认为编译器会将关键字转换为线程的创建,但根据白皮书和 Anders Hejlsberg 的PDC 演示文稿(31:00),异步操作完全发生在主线程上。
如何在同一线程上并行执行操作?它在技术上是如何实现的,以及在 IL 中实际翻译的功能是什么?
它的工作方式类似于yield return
C# 2.0 中的关键字。
异步方法实际上不是普通的顺序方法。它被编译成具有某些状态的状态机(对象)(局部变量被转换为对象的字段)。两次使用之间的每个代码块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
,它将完全在单个线程上运行。
C# 中的异步编程模型非常接近 F# 异步工作流(实际上,除了一些技术细节之外,它本质上是相同的),并且使用编写响应式单线程 GUI 应用程序async
是一个非常有趣的领域——至少我认为所以 - 例如看这篇文章(也许我现在应该写一个 C# 版本:-))。
翻译类似于迭代器 (and yield return
),事实上,之前可以使用迭代器在 C# 中实现异步编程。不久前我写了一篇关于这个的文章——我认为它仍然可以让你对翻译的工作原理有所了解。
如何在同一线程上并行执行操作?
你不能。异步不是“并行”或“并发”。异步可能是通过并行实现的,也可能不是。它可以通过将工作分成小块来实现,将每个工作块放在一个队列中,然后在线程碰巧没有做任何其他事情时执行每个工作块。
我的博客上有一系列关于这些东西如何工作的文章;与这个问题直接相关的问题可能会在下周星期四出现。手表
详情。
据我了解,async
andawait
关键字的作用是每次async
方法使用await
关键字时,编译器都会将该方法的其余部分转换为在异步操作完成时安排的延续。这允许async
方法立即返回调用者并在异步部分完成后恢复工作。
根据可用的文件,它有很多细节,但除非我弄错了,否则这就是它的要点。
在我看来,异步方法的目的不是并行运行大量代码,而是将异步方法分成许多小块,可以根据需要调用。关键是编译器将使用任务/延续来处理所有复杂的回调连接。这不仅降低了复杂性,而且允许异步方法或多或少地像传统的同步代码一样编写。