2014-01-28 94 views
4

試圖理解爲什麼.NET實現他們的方式async-await極簡主義實現異步等待

當改變的代碼使用異步等待下一個簡單的部分,好像是最需要的努力是爲紀念這兩個調用,並異步等待指令調用的方法:

private async void OnGuiClick(object sender, EventArgs args) 
{ 
    textBox1.Text = await Work(); 
} 

private async Task<string> Work() 
{ 
    await Task.Delay(2000); 
    return "Result"; 
} 

爲什麼。 NET堅持兩者? ie用一個關鍵字指定一個表達式時,必須立即在一個工作線程上異步評估一個表達式 - 當調用GUI線程被釋放以執行其他任務時,將被重新連接以執行剩餘的代碼一旦工作者線程完成。

是否有更簡單或更好的方式分配工作線程來處理Work方法,然後自動(無需訴諸Invoke(...))確保相同的調用GUI線程處理結果? 爲什麼不能是這樣的:?

private void OnGuiClick(object sender, EventArgs args) 
{ 
    textBox1.Text = <'some async directive'> Work(); 
} 

private string Work() 
{ 
    Thread.Sleep(2000); 
    return "Result"; 
} 

(該MSDN documentation指出,編譯器將執行代碼同步,如果目標不包含的await語句 - 但隨後又有什麼意義 - 當然了的await異步關鍵字僅用於爲什麼使它變得如此複雜,而不是使用單個指令?)

+1

Eric Lippert發佈​​了一個體面的[博客文章](http://blogs.msdn.com/b/ericlippert/archive/2010/10/29/asynchronous-programming-in-c-5-0-part-two -whence-await.aspx)有些時間可能值得閱讀,例如:「該方法的」異步「修飾符並不意味着」此方法自動調度爲異步運行在工作線程上「」和「整個儘可能多地保留在當前線程上的異步方法。「 –

+0

謝謝 - 這篇文章確實有所幫助:await不會創建工作線程,它會使用當前線程。異步不保證異步實現(即使編譯器會發出警告),開發人員需要確保異步方法正確異步。 – Fortmann

+0

可能的重複[爲什麼async關鍵字存在](http://stackoverflow.com/questions/9225748/why-does-the-async-keyword-exist) –

回答

3

你做出了一個好例子 - 我相信編譯器只需要真正需要「await」關鍵字。我不認爲它關心「異步」修飾符。

但是,編譯器堅持要求用「異步」修飾符標記方法是件好事 - 它允許您檢查方法是否將同步/異步運行,而不必深入其實現。它還告訴你,你是否必須/能夠await它。我相信這是強制使用這兩個關鍵字的原因,而不僅僅是一個。

一個類似的情況是:爲什麼需要使用「公共」訪問修飾符標記接口實現方法,儘管不能被設置爲private/internal/protected/protected internal?似乎有多餘的權利?但是,它的確提高了可讀性。

+1

這是我的印象,它被添加,以防止破壞現有的代碼...你可能會遇到各種問題,如果你有一個叫await的變量! – Liath

+0

@dcastro,同意,你提到的原因是有道理的,這些限制提供了價值。我真正想要的是(通常不是),這是一個簡單的指令,如上所述。即我不在乎被調用的方法是異步/異步...我告訴編譯器在另一個工作線程上運行它,無論如何,然後再次掛接相同的調用GUI線程。真的沒有簡單的方法來做到這一點? – Fortmann

+1

@Fortmann最簡單的方法是'等待Task.Run(...);',這並不複雜得多。另外請注意,'await'關鍵字並不一定意味着被調用的方法**將**在另一個線程上運行。如果方法返回的'Task'已經完成,那麼'await'將簡單地解開結果(如果有的話)並繼續,而不暫停當前線程。例如,該方法可能會返回'Task.FromResult(「hi」);' – dcastro

1

指定async關鍵字是立即暗示此方法的內部必須從頭開始重寫以支持async/await模型。正如你可能知道的那樣,生成的IL看起來很像你的原始方法。你可能會認爲這種重寫也可能是隱含的,但從某種意義上來說,明確地允許這種情況發生。

在另一方面,你有一個正確的觀點:當使用yield關鍵字,它也略微類似於async模型,它也創造了一個狀態機隱含實施IEnumerable類似的事情發生。並且在這種方法之前不存在要求放置關鍵字enumerated的要求。

+0

我的理解是缺乏的:等待本身與分配工作線程無關。 async關鍵字對我有點誤導,因爲它不保證異步操作(異步方法的開發人員對此負責)。如果解釋正確,我明白爲什麼顯式標記是好的,即明確標記某些內容是好的,因爲它爲調用者提供了更多信息。 – Fortmann

2

關於這個問題,我有一個blog post。主要原因是向後兼容性(允許await關鍵字爲上下文關鍵字)。閱讀代碼時,將async關鍵字作爲指標也很好。

另見Eric Lippert's blog post關於這個問題,以及他的,Channel9MSDN forumsright here on SOcomments on another post

+0

您的博客很好,並解釋了爲什麼某些替代方法無效(尤其是等待和推斷異步)。更具體地說,我同意Adelphus從SO主題的推理 - 我寧願單一簡化指令*另外*(替代)異步/等待。確切知道它會做什麼以及其含義(請參閱我的問題的第二個代碼塊)。 – Fortmann

+0

'async'不暗示線程。完全一樣。如果你想在後臺線程上工作,然後同步回UI線程,那麼只需執行'等待Task.Run'。 「任務」。Run'在後臺線程上工作,'await'允許UI線程(異步)等待這個工作。 –

+1

@Fortmann:您可能會發現我的['async' intro](http://blog.stephencleary.com/2012/02/async-and-await.html)有幫助。 –