前幾天在用線程池執行一些任務時運到一種情形,就是回調方法中使用到了異步方法,但是回調方法貌似不支援 async await Task.Result GetAwaiter.GetResult()
的寫法。這時候我應該如何處理呢?是使用
來擷取傳回結果,還是使用
呢?本文就來探讨下吧。
作者:依樂祝
原文位址:https://www.cnblogs.com/yilezhu/p/13168337.html
這裡先上我這種場景的僞代碼:
ThreadPool.QueueUserWorkItem(ExcuteScanProcess, node);
在
ExcuteScanProcess
這個回調方法中
private void ExcuteScanProcess(object state)
{
……其他處理……
repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult();
……其他處理……
}
如上圖所示
repository.UpdateAsync(node)
屬于一部方法,這時候我想要等待它異步執行完成之後再執行後續的邏輯。這時候我有兩種選擇,是直接
repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult();
好呢,還是
repository.UpdateAsync(node).ConfigureAwait(false).Result;
好呢?
為此我查找了相關的資料,對它倆的差別做一個簡單的總結:
其實這兩個使用方式是差不多的。不過,還是有一點小小的差別的:如果任務失敗,
Task.GetAwaiter().GetResult()
會直接抛出異常,而
Task.Result
則會把異常包裝在
AggregateException
中。從這個角度說
Task.GetAwaiter().GetResult()
要優于
Task.Result
。畢竟它少了異常的包裝操作,即直接抛出異常,而不是把異常包裝在
AggregateException
中。
下面的引言解釋了為什麼
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()
作者:依樂祝(祝雷)
出處:https://www.cnblogs.com/yilezhu
聯系:[email protected] .NET Core實戰項目交流群:637326624 微信:jkingzhu
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如有問題或建議,請多多賜教,非常感謝。