我无法理解GetAwaiter().GetResult()和.Result都不能正常工作,但Task.Run(await ()=> nameOfMethodTobeCalled()).Result可以正常工作的原因是什么?

4
在我的asp.net应用程序中,我调用了添加到我的应用程序中的nuget包中的一些异步方法。现在我有一个同步方法,需要调用我添加的dll的异步方法。所以我调用了那些方法并使用以下代码检索结果:

var value = myDllClient.MyMethod().GetAwaiter().GetResult(); 和
var value = myDllClient.MyMethod().Result;, 但是这些都没有起作用,线程进入了无限期的过程。我从未收到任何东西。所以我使用了以下代码:

var value = Task.Run(async ()=> await myDllClient.MyMethod()).Result; 令人惊讶地正常工作。 我不知道它是如何工作的? 有人能帮助我理解这个谜吗?

提前致谢

无法工作 - 您的意思是代码停留在.GetResult().Result行上,无法继续执行吗? - Alexander Goldabin
https://dev59.com/LFkT5IYBdhLWcg3wIsSw - Hans Passant
我从 .GetResult() 的丢失的调用中没有收到任何东西。 - Mukeem Ahmed
2个回答

8

所以我调用了那些方法,并使用以下方式检索结果

更好的解决方案是使用 await允许异步自然地在代码库中增长。如果你确实需要进行同步-over-async,那么 直接阻塞可能会导致死锁

await 默认会捕获上下文, 在你的情况下,MyMethod 中的 await 捕获了一个 ASP.NET 请求上下文,这在 pre-Core 版本的 ASP.NET 中存在。然后,调用代码通过调用 GetResult()/Result 阻塞了该请求上下文中的线程。稍后,当 await 准备好继续时,它将 MyMethod 的其余部分安排到该上下文中。但是,由于有一个线程在等待 MyMethod 完成而被阻塞在该上下文中,因此它永远不会运行。

< p > Task.Run 不会死锁的原因是因为 MyMethod 使用线程池上下文而不是 ASP.NET 请求上下文。 这是执行同步-over-异步的 "线程池 hack" 方法。 但是, Task.Run 不建议在 ASP.NET 上使用; 如果可能,请更改代码以使用 await 。 < /p >

无法将整个代码更改为异步,因为我正在使用基于asp.net的非常旧的Microsoft服务。现在我需要实现其中一个新的dll。如果不喜欢使用Task.Run,则应该使用什么,因为我无法全部转换为await? 感谢您上面的出色指导@Stephen Cleary。 - Mukeem Ahmed
1
在这种情况下,我会使用类似于这个NoContext方法的东西。 - Stephen Cleary

2

通过将您的调用包装在 Task.Run 中,您可以使该代码与 ASP.NET 的 SynchronizationContext 隔离开来,从而避免死锁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接