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

相关文章
相关标签/搜索