Task.FromResult 用法與注意事項
文章目錄
Task
類別有一個靜態方法可用來傳回已完成的工作,這個方法是 FromResult()
。底下是一個簡單範例:Task
<
int
>
task1
=
Task
.
FromResult
(
10
);
什麼時候會用到它呢?一個常見的應用場合是:在非同步方法中,希望以同步的方式傳回結果。舉例來說,假設你現在要設計一個支援非同步處理的快取物件,你先定義了如下介面:
這表示,你預期將來實作
IMyCache
介面時,GetDataAsync
會是個非同步方法。然而,在某種特殊情況下(例如撰寫單元測試),你可能不需要複雜的非同步操作,而只需要直接傳回一個現成的結果。那麼,在撰寫 GetDataAsync
方法時,便可以用上 Task.FromResult
。如下所示:以下程式碼則示範了如何在 Console 應用程式中使用
MyCache
類別的 GetDataAsync
方法: 等等,上述範例的寫法其實有個問題:在沒有非同步操作的地方多餘地使用了
async
和 await
關鍵字。接著要繼續討論這個問題。不要 await Task.FromResult 呼叫
MyCache
類別的人,那麼,你自然知道你寫的 GetDataAsync
方法其實並沒有執行任何非同步工作,因為它是呼叫 Task.FromResult
來直接(立刻)傳回一個已經完成的工作。然而,剛才的 GetDataAsync
方法卻使用了 async
和 await
關鍵字,而這兩個關鍵字會使編譯器產生一些額外的程式碼,以便用來處理非同步呼叫的等待以及環境切換等處理。既然 Task.FromResult
會直接傳回現成的 Task
物件,那麼編譯器所產生的那些額外的程式碼也就都是多餘的了。簡單地說,我們應該遵循這個建議:不要
await
一個 Task.FromResult
呼叫。因此,先前的
GetDataAsync
方法應該把 async
和 await
去掉,變成這樣:你可以看到,在定義
IMyCache
介面時,雖然預期 GetDataAsync
是個非同步方法(注意方法名稱有 Async
後綴),但實作時仍有可能採取同步的方式——當你看到這樣的寫法時,應特別留意是否無意間在非同步呼叫的流程中混雜了同步/阻斷式呼叫,例如底下這個錯誤示範:參考資料