在默認狀況下,一個 async 方法在被 await 調用後恢復運行時,會在原來的上下文中運行。
爲了不在上下文中恢復運行,可以讓 await 調用 ConfigureAwait 方法的返回值,參數 continueOnCapturedContext
設爲 false :html
async Task ResumeOnContextAsync () { await Task.Delay (TimeSpan.FromSeconds (1)); // 這個方法在同一個上下文中恢復運行。 } async Task ResumeWithoutContextAsync () { await Task.Delay (TimeSpan.FromSeconds (1)).ConfigureAwait (false); // 這個方法在恢復運行時,會丟棄上下文。 }
做者Stephen提到,當在UI線程大量使用async方法,可能須要考慮線程切換致使上下文恢復致使的性能消耗。固然性能消耗問題不會是單一的緣由致使,代碼的優化永無止境。編程
可能會有人對性能消耗的理解不太具體,大概解釋一下,async方法會生成一個狀態機,該狀態機多是一個class或者struct用來存儲上下文信息,這些都要消耗存儲空間和進行後續的GC回收。
關於狀態機的更多信息能夠訪問《C#併發編程經典實例》學習筆記—異步編程關鍵字 Async和Await 查看。併發
Stephen提到UI線程中若是每秒有1000個任務就太多了。這個結論來自於視頻Tip 6: Async library methods should consider using Task.ConfigureAwait(false)異步
文章Talk: Async best practices給出的第6條建議提到做爲一個類庫提供者,應該須要注意ConfigureAwait的問題,避免該類庫的使用者在UI線程使用該類庫時產生額外的性能消耗。還提到類庫使用者對異步方法不當的使用時將會致使死鎖,而避免該類死鎖的最佳辦法是,參數
continueOnCapturedContext 設爲 false 即便用ConfigureAwait (false)
。async
我的總結一下不當的使用包括但不限於如下幾類:ide
ConfigureAwait (false)
。Task.Wait()
或者Task.Result
。參考文章:異步編程