2015-05-29 35 views
3

我想了解異步/等待,並閱讀了大量的文章,但我仍然對同步/異步性質感到困惑。如果一個異步方法是單線程的,它如何在後臺運行?

我有以下的測試控制檯應用程序:

static void Main(string[] args) 
{ 
    var test = FooAsync(); 
    Console.WriteLine("After FooAsync"); 

    for (int i = 0; i < 100; i++) 
     Console.WriteLine("After that"); 

    Console.ReadKey(); 
} 

private static async Task FooAsync() 
{ 
    Console.WriteLine("Before delay"); 
    await Task.Delay(1); 
    Console.WriteLine("After delay"); 
} 

的代碼提供的線沿線的輸出:

Before delay 
After FooAsync 
After that 
After that 
After that 
After that 
After delay 
After that 
. 
. 

據我所知,異步/ AWAIT將創建一個單獨的線程處理,並且在FooAsync點達到await Task.Delay(1)一行,它將返回到Main,因爲任務尚未完成,但是,因爲我們只運行在一個單獨的讀有人可以解釋什麼觸發FooAsync方法在Main之內的某個任意點恢復,然後Main可以繼續?

更新 我拿回來,i3arnon和dariogriffo是正確的。該代碼確實使用了多個線程(正如我之前看到的那樣,在調試器中查看或者按照kha的建議做了顯而易見的事情)。我被以下頁面的線程部分所困惑,https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads沒有意識到「延續」實際上指的是一旦任務「等待」完成就立即運行延續任務計劃。

+1

的答案是正確的,但如果你想完全理解,這個替換您的FooAsync:'私有靜態異步任務FooAsync(){ Console.WriteLine(+ Thread.CurrentThread.ManagedThreadId「延遲之前」) ; await Task.Delay(1); Console.WriteLine(「After delay on」+ Thread.CurrentThread.ManagedThreadId);並且看到之前和之後都是在不同的線程上完成的。 – kha

回答

5

這不是單線程

當延遲任務完成後,其餘方法發佈到ThreadPool並與您的主線程同時運行。這裏的「觸發器」是在Task.Delay內使用的內部System.Threading.Timer的回調。

此行爲取決於SynchronizationContext。在UI環境中,這將被髮布到相同的UI線程,並且必須等到該線程空閒爲止。

,如果您一直在等待任務從FooAsync返回然後你只會有一個線程運行每次

+0

請參閱[本答案](http://stackoverflow.com/a/9212343/1497596)瞭解如何等待'Main'內的'FooAsync'返回的任務,以便在主線程上運行'FooAsync'的延續。另外,請注意,不等待'FooAsync','FooAsync'拋出的異常將被默默吞下。 – DavidRR

2

異步/等待可能會創建新線程或不,它取決於操作的性質。 如果操作是一個IO(例如磁盤/網絡操作)可能被編碼的方式,它不會旋轉一個新的線程。你可以在這裏閱讀:

The async and await keywords don't cause additional threads to be created?

如果你創建自己的異步操作,你創建一個線程,這是一個不同的故事,這就是爲什麼你不應該在同步

http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

異步做

你也可以檢查這一點,但使用Thread.CurrentThread來獲取進程的Id。 (將它添加到Console.WriteLine中)

0

關鍵字asyncawait創建新線程是一個相當常見的誤解。他們不。

線程通過運行Task創建。在這種情況下,該線程由Task.Delay調用創建。通過i3arnon

相關問題