我最近阅读了一些使用了大量异步方法的代码,但有时需要同步执行它们。代码如下:

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

是一样的吗

Foo foo = GetFooAsync(...).Result;

当前回答

Task. getawaiter (). getresult()优先于Task。等待和任务。结果,因为它传播异常,而不是将异常包装在AggregateException中。但是,这三种方法都可能导致死锁和线程池不足问题。应该避免使用async/await。

下面的引用解释了为什么Task。等待和任务。结果不只是包含Task.GetAwaiter(). getresult()的异常传播行为(由于“非常高的兼容性栏”)。

As I mentioned previously, we have a very high compatibility bar, and thus we’ve avoided breaking changes. As such, Task.Wait retains its original behavior of always wrapping. However, you may find yourself in some advanced situations where you want behavior similar to the synchronous blocking employed by Task.Wait, but where you want the original exception propagated unwrapped rather than it being encased in an AggregateException. To achieve that, you can target the Task’s awaiter directly. When you write “await task;”, the compiler translates that into usage of the Task.GetAwaiter() method, which returns an instance that has a GetResult() method. When used on a faulted Task, GetResult() will propagate the original exception (this is how “await task;” gets its behavior). You can thus use “task.GetAwaiter().GetResult()” if you want to directly invoke this propagation logic.

https://devblogs.microsoft.com/pfxteam/task-exception-handling-in-net-4-5/

“GetResult”实际上意味着“检查任务中的错误” 一般来说,我尽量避免异步任务上的同步阻塞。然而,在一些情况下,我确实违反了这一原则。在这些罕见的情况下,我首选的方法是GetAwaiter(). getresult(),因为它保留任务异常,而不是将它们包装在AggregateException中。

https://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html

其他回答

Task. getawaiter (). getresult()优先于Task。等待和任务。结果,因为它传播异常,而不是将异常包装在AggregateException中。但是,这三种方法都可能导致死锁和线程池不足问题。应该避免使用async/await。

下面的引用解释了为什么Task。等待和任务。结果不只是包含Task.GetAwaiter(). getresult()的异常传播行为(由于“非常高的兼容性栏”)。

As I mentioned previously, we have a very high compatibility bar, and thus we’ve avoided breaking changes. As such, Task.Wait retains its original behavior of always wrapping. However, you may find yourself in some advanced situations where you want behavior similar to the synchronous blocking employed by Task.Wait, but where you want the original exception propagated unwrapped rather than it being encased in an AggregateException. To achieve that, you can target the Task’s awaiter directly. When you write “await task;”, the compiler translates that into usage of the Task.GetAwaiter() method, which returns an instance that has a GetResult() method. When used on a faulted Task, GetResult() will propagate the original exception (this is how “await task;” gets its behavior). You can thus use “task.GetAwaiter().GetResult()” if you want to directly invoke this propagation logic.

https://devblogs.microsoft.com/pfxteam/task-exception-handling-in-net-4-5/

“GetResult”实际上意味着“检查任务中的错误” 一般来说,我尽量避免异步任务上的同步阻塞。然而,在一些情况下,我确实违反了这一原则。在这些罕见的情况下,我首选的方法是GetAwaiter(). getresult(),因为它保留任务异常,而不是将它们包装在AggregateException中。

https://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html

https://github.com/aspnet/Security/issues/59

最后一点:你应该避免使用Task。结果和任务。等 尽可能多的,因为它们总是将内部异常封装在 并将该消息替换为通用消息(one或 出现了更多错误),这使得调试更加困难。即使 同步版本不应该经常使用,应该强烈使用 请考虑使用Task.GetAwaiter(). getresult()。

如前所述,如果你可以使用await。如果你需要像你提到的. getawaiter (). getresult()那样同步运行代码,. result或. wait()有死锁的风险,正如许多人在评论/回答中所说的那样。因为我们大多数人都喜欢一行程序,所以你可以在。net 4.5中使用它们。

通过async方法获取一个值:

var result = Task.Run(() => asyncGetValue()).Result;

同步调用异步方法

Task.Run(() => asyncMethod()).Wait();

由于使用Task.Run,不会出现死锁问题。

来源:

https://stackoverflow.com/a/32429753/3850405

更新:

如果调用线程来自线程池,则可能导致死锁。发生如下情况:一个新任务排队到队列的末尾,最终将执行该任务的线程池线程被阻塞,直到该任务执行为止。

来源:

https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d

编辑:这是我13岁时写的,现在已经过时了。我推荐Nitin Agarwal的答案。

差不多。但有一个小区别:如果Task失败,GetResult()将直接抛出异常,而Task。结果将抛出AggregateException。然而,当它是异步的时候,使用它们有什么意义呢?更好的100倍选择是使用await。

另外,您不应该使用GetResult()。它仅供编译器使用,而不是供您使用。但是如果你不想要恼人的AggregateException,那就使用它。

If a task faults, the exception is re-thrown when the continuation code calls awaiter.GetResult(). Rather than calling GetResult, we could simply access the Result property of the task. The benefit of calling GetResult is that if the task faults, the exception is thrown directly without being wrapped in AggregateException, allowing for simpler and cleaner catch blocks. For nongeneric tasks, GetResult() has a void return value. Its useful function is then solely to rethrow exceptions.

源码:c# 7.0简写