C# Task.Result 和 .GetAwaiter.GetResult() 一样吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17284517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:02:09  来源:igfitidea点击:

Is Task.Result the same as .GetAwaiter.GetResult()?

c#async-await

提问by Jay Bazuzi

I was recently reading some code that uses a lot of async methods, but then sometimes needs to execute them synchronously. The code does:

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

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

Is this the same as

这是否与

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

回答by It'sNotALie.

Pretty much. One small difference though: if the Taskfails, GetResult()will just throw the exception caused directly, while Task.Resultwill throw an AggregateException. However, what's the point of using either of those when it's async? The 100x better option is to use await.

差不多。但是有一个小区别:如果Task失败,GetResult()只会抛出直接引起的异常,而Task.Result会抛出一个AggregateException. 但是,当它是时使用其中任何一个的意义async何在?100 倍更好的选择是使用await.

Also, you're not meant to use GetResult(). It's meant to be for compiler use only, not for you. But if you don't want the annoying AggregateException, use it.

此外,您不打算使用GetResult(). 它仅供编译器使用,不适用于您。但是,如果您不想烦人AggregateException,请使用它。

回答by scyuo

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

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

"One last remark: you should avoid using Task.Resultand Task.Waitas much as possible as they always encapsulate the inner exception in an AggregateExceptionand replace the message by a generic one (One or more errors occurred), which makes debugging harder. Even if the synchronous version shouldn't be used that often, you should strongly consider using Task.GetAwaiter().GetResult()instead."

“最后一句话:你应该尽可能避免使用Task.Resultand Task.Wait,因为它们总是将内部异常封装在 an 中 AggregateException,并将消息替换为通用的(发生一个或多个错误),这使得调试更加困难。即使同步版本应该不经常使用,您应该强烈考虑Task.GetAwaiter().GetResult()改用。”

回答by Nitin Agarwal

Task.GetAwaiter().GetResult()is preferred over Task.Waitand Task.Resultbecause it propagates exceptions rather than wrapping them in an AggregateException. However, all three methods cause the potential for deadlock and thread pool starvation issues. They should all be avoided in favor of async/await.

Task.GetAwaiter().GetResult()优先于Task.Wait并且Task.Result因为它传播异常而不是将它们包装在AggregateException. 但是,所有三种方法都可能导致死锁和线程池饥饿问题。他们都应该避免使用async/await.

The quote below explains why Task.Waitand Task.Resultdon't simply contain the exception propagation behavior of Task.GetAwaiter().GetResult()(due to a "very high compatibility bar").

下面的引用解释了为什么Task.Wait并且Task.Result不简单地包含异常传播行为Task.GetAwaiter().GetResult()(由于“非常高的兼容性栏”)。

As I mentioned previously, we have a very high compatibility bar, and thus we've avoided breaking changes. As such, Task.Waitretains 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.

正如我之前提到的,我们有一个非常高的兼容性标准,因此我们避免了破坏性更改。因此,Task.Wait保留其始终环绕的原始行为。但是,您可能会发现自己处于某些高级情况下,在这些情况下,您希望行为类似于 使用的同步阻塞Task.Wait,但希望原始异常传播解包而不是将其封装在AggregateException. 为此,您可以直接定位 Task 的 awaiter。当您编写“ 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/

https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

GetResult” actually means “check the task for errors”

In general, I try my best to avoid synchronously blocking on an asynchronous task. However, there are a handful of situations where I do violate that guideline. In those rare conditions, my preferred method is GetAwaiter().GetResult()because it preserves the task exceptions instead of wrapping them in an AggregateException.

GetResult”实际上的意思是“检查任务是否有错误”

一般来说,我尽量避免同步阻塞异步任务。但是,在少数情况下我确实违反了该准则。在那些罕见的情况下,我首选的方法是GetAwaiter().GetResult()因为它保留任务异常而不是将它们包装在AggregateException.

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

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

回答by Nuri Tasdemir

Another difference is when asyncfunction returns just Taskinstead of Task<T>then you cannot use

另一个区别是当async函数只返回Task而不是Task<T>then 你不能使用

GetFooAsync(...).Result;

Whereas

然而

GetFooAsync(...).GetAwaiter().GetResult();

still works.

仍然有效。

I know the example code in the question is for the case Task<T>, however the question is asked generally.

我知道问题中的示例代码是针对 case 的Task<T>,但是一般会问这个问题。

回答by Ogglas

As already mentioned if you can use await. If you need to run the code synchronously like you mention .GetAwaiter().GetResult(), .Resultor .Wait()is a risk for deadlocks as many have said in comments/answers. Since most of us like oneliners you can use these for .Net 4.5<

如前所述,如果您可以使用await. 如果您需要像您提到的那样同步运行代码.GetAwaiter().GetResult().Result或者.Wait()像许多人在评论/答案中所说的那样存在死锁风险。由于我们大多数人都喜欢oneliners,因此您可以将它们用于.Net 4.5<

Acquiring a value via an async method:

通过异步方法获取值:

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

Syncronously calling an async method

同步调用异步方法

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

No deadlock issues will occur due to the use of Task.Run.

不会因为使用Task.Run.

Source:

来源:

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

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

回答by Ali Abdollahi

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.

如果任务出错,则在继续代码调用 awaiter.GetResult() 时重新抛出异常。我们可以简单地访问任务的 Result 属性,而不是调用 GetResult。调用 GetResult 的好处是,如果任务出错,则直接抛出异常,而不用包裹在 AggregateException 中,允许更简单、更清晰的 catch 块。

对于非通用任务,GetResult() 有一个 void 返回值。它的有用功能就是重新抛出异常。

source : c# 7.0 in a Nutshell

来源:C# 7.0 简而言之