2016-05-22 46 views
3

在試圖理解異步/等待我做了一個示例WPF應用程序有一個按鈕。當點擊它會做一些「工作」:異步等待在預期的線程上不執行

private async void goButtonClicked(object sender, EventArgs e) 
     { 

      WhatThreadAmI(); 
      var task = populateRawData().ConfigureAwait(false); 
      WhatThreadAmI(); 
      BusyIndicator.IsBusy = true;  

      await task; 
      WhatThreadAmI(); //this isnt on the main thread - why?? 
      BusyIndicator.IsBusy = false; 

      Console.WriteLine("fin"); 
     } 

的「WhatThreadAmI」僅僅是當前比較線程到UI線程我節省初始化。

public bool IsMainThread => uiThread == Thread.CurrentThread; 

我預計這個輸出是真 - 真 - 真,隨着填入原始數據法「WhatThreadAmI」調用返回false。

實際發生什麼是真正的 - 真 - 假,隨着填入原始數據法「」 WhatThreadAmI」調用返回true

我知道我必須在這裏失去了一些非常基本的,但有人請幫助。我明白了是怎麼回事?

+0

[異步不是線程](http://stackoverflow.com/q/17661428/11683)。 – GSerg

+3

即使是這樣,當您創建任務時,確實會說'.ConfigureAwait(false)',這意味着「我不需要在原始上下文中恢復」。只要你「等待」那個任務,你的環境就會改變,所以在這裏就不足爲奇了。當你簡單地創建任務但不等待它時,上下文不會改變,所以兩個第一個'WhatThreadAmI'返回'true'。 – GSerg

+0

有道理 - 謝謝! – smodle

回答

0

Task對象是在.NET線程池的抽象。一個線程可以開始執行代碼,等待一個不完成任務,並從不同的線程恢復。

通過這種方式,您可以最大限度地利用您的CPU而不會阻塞o意味着任務。一個可用的線程將在等待完成時繼續執行任務。它可能是過去執行任務的線程,它可能不是。

+1

我喜歡這個答案,因爲它是問題中隱含的關鍵細節的核心。如果您依賴特定線程的某些行爲,那麼Async Await不是您的解決方案。我將Async Await描述爲「如果可以,請嘗試並行化」。 「隨機」使用線程。這裏有一個設計和體系結構的細節,如果你試圖去理解它,這並不是微不足道的。如果你想了解原始問題是一個很好的問題。爲什麼它在所有環境中都不會如預期那樣是一個很好的例子,原來的問題已經浮出水面。 –

+0

感謝您的擴展,我同意 - 我從根本上誤解了Async/Await的功能,並且此答案確實解決了最初的問題。 – smodle

-1

更改ConfigureAwait(false); ConfigureAwait(true);或者只是刪除它。

4
var task = populateRawData().ConfigureAwait(false); 

ConfigureAwait(false)返回配置任務awaiter是上捕捉的上下文不會恢復。我在我的博客上詳細解釋了how await captures and resumes on context; ConfigureAwait(false)的使用意味着而不是捕獲並恢復上下文。在這種情況下,「上下文」是UI線程。因此,await不會恢復UI線程,因爲ConfigureAwait(false)明確告訴await它不需要。

請注意,該代碼中的task變量確實是而不是包含Task。將ConfigureAwait的結果代入其變量await非常不尋常。下面的例子是等價和 - 我想 - 表達更清楚這是怎麼回事:

WhatThreadAmI(); 
var task = populateRawData(); 
WhatThreadAmI(); 
BusyIndicator.IsBusy = true;  

await task.ConfigureAwait(false); 
WhatThreadAmI(); //this isnt on the main thread - why?? 
BusyIndicator.IsBusy = false; 

換句話說:它ConfigureAwait,不ConfigureTask。它根本不會改變任務; ConfigureAwait只有可以使用await