Task.Result跟 Task.GetAwaiter.GetResult()相同嗎?怎麼選?

前幾天在用線程池執行一些任務時運到一種情形,就是回調方法中使用到了異步方法,可是回調方法貌似不支持async await的寫法。這時候我應該如何處理呢?是使用Task.Result來獲取返回結果,仍是使用GetAwaiter.GetResult()呢?本文就來探討下吧。html

做者:依樂祝node

原文地址:http://www.javashuo.com/article/p-eeetmnqw-kr.htmlc#

這裏先上我這種場景的僞代碼:異步

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()

相關文章
相關標籤/搜索