2016-02-18 78 views
6

我創建下面的代碼:異步和等待是單線程真的嗎?

using System; 
using System.Threading.Tasks; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main() 
     { 
     Console.WriteLine("M Start"); 
     MyMethodAsync(); 
     Console.WriteLine("M end"); 
     Console.Read(); 
     } 

    static async Task MyMethodAsync() 
    { 
     await Task.Yield(); 
     Task<int> longRunningTask = LongRunningOperationAsync(); 
     Console.WriteLine("M3"); 
     //and now we call await on the task 
     int result = await longRunningTask; 
     //use the result 
     Console.WriteLine(result); 
    } 

     static async Task<int> LongRunningOperationAsync() 
     { 
     await Task.Delay(1000); 
     return 1; 
     } 
    } 
} 

輸出:

M Start 
M end 
M3 
1 

這很好,但是當我看在線程分析它顯示了這個: enter image description here 然後將此: enter image description here 而那麼這個: enter image description here

所以它看起來像我產生線程,但是從MSDN說:

從異步編程與異步和等待:線程

異步和等待關鍵字不會造成額外的線程是 創建。異步方法不需要多線程,因爲異步方法不會在其自己的線程上運行。該方法在當前的 同步上下文上運行,並僅在 方法處於活動狀態時纔在線程上使用時間。您可以使用Task.Run將CPU綁定的工作移動到後臺線程,但後臺線程無助於僅等待結果可用的進程 。

我是否缺少或不理解某些東西? 謝謝。

+2

它使用存在線程池中的線程,而不是創建一個 –

+1

這看起來像是Visual Studio中非常漂亮的窗口。對不起這個題外話題,但哪個版本支持它? –

+0

用'Thread.CurrentThread.ManagedThreadId'裝飾你的輸出,你可能會看到正在使用3個線程。 –

回答

7

我在我的博客上解釋how async and await work with threads and contexts。總之,當await需要等待異步操作完成時,它將「暫停」當前的方法並且(默認情況下)捕獲「上下文」。

當異步操作完成時,使用該「上下文」來恢復方法async。這個「上下文」是SynchronizationContext.Current,除非它是null,在這種情況下它是TaskScheduler.Current。就你而言,上下文最終成爲線程池上下文,因此方法的其餘部分將被髮送到線程池。如果您從UI線程運行相同的代碼,則上下文將是UI上下文,並且所有方法都將在UI線程上恢復。

2

async和await關鍵字不會導致創建額外的線程。

是的。它將CPU綁定或I/O綁定工作從進程的線程池移到其他線程,以便它不會在UI線程或當前同步上下文中執行,它不會創建MSDN描述中所指的新線程。

+0

但如果所有的線程正在消耗,那麼它會等待。對? –

+1

這只是錯誤的。任務在當前的同步上下文上執行。只有在使用基於線程池的同步上下文時,纔會使用不同的線程,否則一切都會在主線程上使用隊列完成。閱讀關於「continuation-passing style」的內容,這是async在下面的工作方式。 –