1. 程式人生 > >15.6.1 【Task使用】基於任務的非同步模式

15.6.1 【Task使用】基於任務的非同步模式

  C# 5非同步函式特性的一大好處是,它為非同步提供了一致的方案。但如果在命名非同步方法以及 觸發異常等方面做法存在著差異,則很容易破壞這種一致性。微軟因此釋出了基於任務的非同步模 式(Task-based Asynchronous Pattern,TAP),即提出了每個人都應遵守的約定。TAP有單獨的文 件(http://mng.bz/B68W),MSDN中也有它的頁面(http://mng.bz/4N39)。

  基於IO的操作會將工作移交給硬碟或其他計算機,這非常適合非同步,而且沒有明顯的缺點。 CPU密集型的任務就不那麼適合了。可以很輕鬆地將一些工作移交給執行緒池,在.NET 4.5中也要 比以前更加簡單,這都要感謝 Task.Run 方法,但使用程式碼庫來實現這一點,相當於為呼叫者做 了決定。不同的呼叫者可能會有不同的需求。如果僅僅暴露同步風格的方法,相當於為呼叫者提 供了靈活性,以保證其以最適合的方式進行工作。它們可以在需要時開始一個新任務,如果可以 接受當前執行緒在一段時間內忙於執行方法,也可以實現同步呼叫。

1         public static async Task<int> ProcessRecords()
2         {
3             List<Record> records = await FetchRecordsAsync().ConfigureAwait(false);
4             //記錄處理
5             await SaveResultsAsync(results).ConfigureAwait(false);
6             //讓呼叫者知道處理了多少條記錄
7             return
records.Count; 8 }

  該方法大部分程式碼線上程池執行緒上執行。由於並沒有要求在原始執行緒中執行,因此這正是我 們想要的結果。(專業術語叫做該操作沒有執行緒親和力(thread affinity)。)但這並不會影響呼叫 者,如果非同步UI方法等待的是呼叫 ProcessRecords 的結果,則該非同步方法將繼續在UI執行緒上執 行。只有在 ProcessRecords 內部的程式碼宣告其不關心執行上下文時,才會在執行緒池執行緒上執行。

  有爭議的是,沒有必要在第二個 await 表示式處呼叫 ConfigureAwait ,因為所剩工作已經 不多了,但通常來說我們應該在每個 await 表示式處呼叫該方法,而保持一致是個好習慣。如果 想為呼叫者提供方法執行上下文的靈活性,可將其作為非同步方法引數。

  注意, ConfigureAwait 只會影響執行上下文的同步部分。而有關模擬(impersonation)等 其他部分,傳播則並不關心,15.6.4節將詳細介紹相關內容。