C#异步 - 它是如何工作的?

时间:2010-10-28 21:47:43

标签: c# .net vb.net asynchronous async-await

Microsoft今天(2010年10月28日)宣布Visual Studio Async CTPasyncawait关键字引入C#/ VB以执行异步方法。

首先我认为编译器会将关键字转换为线程的创建但是根据white paper和Anders Hejlsberg的PDC presentation(31:00),异步操作完全发生在主线程上。

如何在同一个线程上并行执行操作?技术上如何可能以及IL中实际翻译的功能是什么?

3 个答案:

答案 0 :(得分:80)

它与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,它将完全在单个线程上运行。

C#中的异步编程模型非常接近F#异步工作流(事实上,除了一些技术细节外,它基本上是相同的),使用async编写反应式单线程GUI应用程序是相当的一个有趣的领域 - 至少我是这么认为的 - 参见例如this article(也许我现在应该写一个C#版本: - ))。

转换类似于迭代器(和yield return),实际上,可以使用迭代器在C#中实现异步编程。我刚才写了an article about that - 我认为它仍然能让你对翻译的工作方式有所了解。

答案 1 :(得分:46)

  

如何在同一个线程上并行执行操作?

你做不到。 异步不是“并行”或“并发”。异步可能是以并行性实现的,也可能不是。它可以通过将工作分解成小块,将每个工作块放在一个队列上,然后在线程碰巧没有做任何其他事情时执行每一块工作来实现。

我的博客上有一系列关于这些东西是如何工作的文章;与这个问题直接密切相关的人可能会在下周四上升。观看

http://blogs.msdn.com/b/ericlippert/archive/tags/async/

了解详情。

答案 2 :(得分:8)

据我了解,asyncawait关键字的作用是,每次async方法使用await关键字时,编译器都将转为剩下的将该方法转换为异步操作完成时计划的延续。这允许async方法立即返回调用方并在异步部分完成时恢复工作。

根据现有的论文,有很多细节,但除非我弄错了,这就是它的要点。

正如我所看到的,异步方法的目的不是并行运行大量代码,而是将异步方法分成许多小块,可以根据需要调用。关键是编译器将使用任务/继续处理所有复杂的回调连接。这不仅降低了复杂性,而且允许异步方法或多或少地像传统的同步代码一样编写。