2010-10-28 66 views
43

微軟宣佈Visual Studio Async CTP今日(2010年10月28日),介紹了asyncawait關鍵字爲異步方法執行C#/ VB。C#異步 - 它是如何工作的?

首先,我認爲編譯器將關鍵字轉換爲創建線程,但根據white paper和Anders Hejlsberg的PDC presentation(在31:00),異步操作完全在主線程上發生。

我怎麼能有一個操作相同的並行線程上執行?它在技術上如何可能以及在IL中實際翻譯的功能是什麼?

回答

73

它的工作原理類似於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#異步工作流程(事實上,除了一些技術細節外,它本質上是一回事),使用async編寫反應性單線程GUI應用程序是一個相當有趣的領域 - 至少我認爲是這樣 - 例如this article(也許我現在應該寫一個C#版本:-))。

該翻譯類似於迭代器(和yield return),事實上,有可能使用迭代器在C#中實現異步編程。前一段我寫了an article about that - 我認爲它仍然可以讓你對翻譯的工作方式有所瞭解。

6

據我瞭解,有什麼asyncawait關鍵字做的是,每一個async方法採用await關鍵字時,編譯器將會把該方法的其餘部分將在完成異步操作時所計劃的延續。這允許async方法立即返回給調用者,並在異步部分完成時恢復工作。

根據現有的文件也有很多細節,但除非我錯了,這是它的要點。

當我看到它的異步方法的目的不是爲了運行大量的並行代碼,但砍異步方法分成若干小塊的,可以根據需要調用。關鍵在於編譯器將使用任務/連續處理所有複雜的回調連線。這不僅降低了複雜度,而且允許像傳統同步代碼那樣或多或少寫入異步方法。

+2

它是如何安排沒有一個單獨的線程?在CLR中是否延續了一個特定的概念,允許一些輕量級的調度? – 2010-10-28 21:55:55

+0

@ 0xA3:我相信論文說異步方法不會在它自己的線程上運行。即就像TPL一樣,根據具體情況,它將是當前線程和線程池線程的混合。 – 2010-10-28 22:00:30

43

如何在同一個線程上並行執行一個操作?

你不行。 異步不是「並行性」或「併發性」。異步可能是用並行來實現的,或者它可能不是。它可以通過將工作分解成小塊,將每個工作塊放到一個隊列中,然後在線程碰巧沒有做其他事情時執行每個工作塊來實現。

我在我的博客上有一系列關於這些東西是如何工作的文章;直接與這個問題密切相關的人可能會在下週的星期四上升。手錶

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

瞭解詳情。