我最近在阅读一些使用很多异步方法的代码,但是有时需要同步执行它们。该代码可以:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
这和
Foo foo = GetFooAsync(...).Result;
async/ await方法)
我最近在阅读一些使用很多异步方法的代码,但是有时需要同步执行它们。该代码可以:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
这和
Foo foo = GetFooAsync(...).Result;
async/ await方法)
Answers:
差不多了 但是有一个小的区别:如果Task失败,GetResult()将仅引发直接导致的异常,而Task.Result将引发AggregateException。但是,在使用它们时有async什么意义呢?最好使用100倍await。
另外,您也不打算使用GetResult()。它只供编译器使用,不适合您。但是,如果您不想烦人AggregateException,请使用它。
async Task单元测试,并且已经有一段时间了。
The 100x better option is to use await.我讨厌这样的陈述,如果我能await在它前面打耳光,我会。但是,当我试图让异步代码来对抗像什么经常发生在我身上的非异步代码工作了很多在Xamarin,我最终不得不用的东西一样ContinueWith不少,以使其不死锁的UI。编辑:我知道这很老了,但是这并不能减轻我的沮丧感,因为对于不能仅仅使用的情况,没有其他选择的答案await。
Task.GetAwaiter().GetResult()优先于Task.Wait,Task.Result因为它传播异常而不是将异常包装在AggregateException。但是,这三种方法都可能导致死锁和线程池不足的问题。应该避免他们都赞成async/await。
下面的引用解释了为什么Task.Wait并且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。
http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html
Task.GetAwaiter().GetResult()等同于await task。我假设在无法用方法标记方法async(例如构造函数)时使用第一个选项。那是对的吗?如果是,那么它就会与最高答案冲突@ It'sNotALie
Task.GetAwaiter().GetResult()与Task.Wait和更等效Task.Result(因为这三个都将同步阻塞并可能产生死锁),但是Task.GetAwaiter().GetResult()具有await任务的异常传播行为。
https://github.com/aspnet/Security/issues/59
“最后一句话:您应该避免使用
Task.Result并且Task.Wait尽可能地避免它们总是将内部异常封装在中,AggregateException并用通用的消息(发生一个或多个错误)替换消息,这会使调试更加困难。即使同步版本不应该不会经常使用,您应该强烈考虑Task.GetAwaiter().GetResult()改为使用。”
Task.WhenAll(task1, task2).GetAwaiter().GetResult();。
另一个区别是当async函数返回Task而不是时,Task<T>您不能使用
GetFooAsync(...).Result;
鉴于
GetFooAsync(...).GetAwaiter().GetResult();
仍然有效。
我知道问题中的示例代码适合这种情况Task<T>,但是问题通常被问到。
Result,GetIntAsync()而返回的结果Task<int>不只是Task。我建议您再次阅读我的答案。
GetFooAsync(...).Result 在return的函数内部Task。现在这很有意义,因为C#中没有void属性(Task.Result是一个属性),但是您当然可以调用void方法。
如前所述,如果可以使用await。如果您需要像您提到的那样同步运行代码.GetAwaiter().GetResult(),.Result或者.Wait()像许多评论/回答中所说的那样存在死锁的风险。由于我们大多数人都喜欢oneliners,因此您可以将其用于.Net 4.5<
通过异步方法获取值:
var result = Task.Run(() => asyncGetValue()).Result;
同步调用异步方法
Task.Run(() => asyncMethod()).Wait();
使用不会出现死锁问题Task.Run。
资源:
如果任务失败,那么当连续代码调用awaiter.GetResult()时,将引发异常。无需调用GetResult,我们可以简单地访问任务的Result属性。调用GetResult的好处是,如果任务失败,则将异常直接引发而不将其包装在AggregateException中,从而允许更简单,更干净的catch块。
对于非常规任务,GetResult()的返回值是无效的。这样,它的有用功能就是仅抛出异常。
源:简而言之的c#7.0
GetResult:“此类型及其成员旨在供编译器使用。” 其他人不应该使用它。