前幾天在用線程池執行一些任務時運到一種情形,就是回調方法中使用到了異步方法,可是回調方法貌似不支持async await
的寫法。這時候我應該如何處理呢?是使用Task.Result
來獲取返回結果,仍是使用GetAwaiter.GetResult()
呢?本文就來探討下吧。html
做者:依樂祝node
這裏先上我這種場景的僞代碼:異步
ThreadPool.QueueUserWorkItem(ExcuteScanProcess, node);
在ExcuteScanProcess
這個回調方法中async
private void ExcuteScanProcess(object state) { ……其餘處理…… repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult(); ……其餘處理…… }
如上圖所示repository.UpdateAsync(node)
屬於一部方法,這時候我想要等待它異步執行完成以後再執行後續的邏輯。這時候我有兩種選擇,是直接線程
repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult();
好呢,仍是code
repository.UpdateAsync(node).ConfigureAwait(false).Result;
好呢?htm
爲此我查找了相關的資料,對它倆的區別作一個簡單的總結:blog
其實這兩個使用方式是差很少的。不過,仍是有一點小小的區別的:若是任務失敗,Task.GetAwaiter().GetResult()
會直接拋出異常,而Task.Result
則會把異常包裝在AggregateException
中。從這個角度說Task.GetAwaiter().GetResult()
要優於Task.Result
。畢竟它少了異常的包裝操做,即直接拋出異常,而不是把異常包裝在AggregateException
中。get
下面的引言解釋了爲何Task.Result
不單單包含Task.GetAwaiter().GetResult()
(因爲「很是高的兼容性」)的異常傳播行爲。
如前所述,咱們有一個很是高的兼容性標準,所以咱們避免了改動。所以,
Task.Wait
保留了始終包裝的原始行爲。可是,您可能會發現本身處在某些高級狀況下,這些狀況下您想要的行爲相似於所採用的同步阻塞Task.Wait
,可是您但願將原始異常展開而不是傳播,而不是將其封裝在AggregateException
中。爲此,您能夠直接定位任務的等待者。當您編寫「await task;
」時,編譯器Task.GetAwaiter()
會將其轉換爲方法的用法,這將返回具備GetResult()
方法的實例。當用於有故障的任務時,GetResult()
將傳播原始異常(這是「await task;
」 如何得到其行爲)。所以,您可使用「task.GetAwaiter().GetResult()
若是您想直接調用此傳播邏輯。
https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/
「
GetResult
」實際上表示「檢查任務是否有錯誤」一般,我會盡力避免對異步任務進行同步阻塞。可是,在少數狀況下,我確實違反了該準則。在那些罕見的狀況下,個人首選方法是
GetAwaiter().GetResult()
由於它保留任務異常,而不是將它們包裝在中AggregateException
。
經過上述內容的闡述,所以在那些必須對異步任務進行同步阻塞的場景中,我選擇使用GetAwaiter().GetResult()
。