在Task.Run(() =>MyTask).结果,等待MyTask和MyTask.Result

本文关键字:MyTask Result 等待 结果 Task Run | 更新日期: 2023-09-27 18:11:18

我甚至不确定我问的问题是否正确,所以请原谅我;下面是我要处理的:

在我的MVC4项目(目标。net 4.5.1)如果我做await SomeAsyncMethod(...),那么任务在后台完成,但似乎永远不会返回。我相信这与线程被返回到池中,然后在另一个线程上恢复有关。我一直在使用的变通方法是使用Thread.Run(() => SomeTask).Result;

所以,我发现自己不得不做Thread.Run(() => SomeAsyncMethod).Result;很多在我的MVC项目,以免我以死锁结束。这难道不是同步运行任务的另一种语法吗?我不确定这是否是MVC 4(相对于MVC 5)的限制,或者这只是api的工作方式。从异步性的角度来看,我这样做是否毫无收获?

我们在这里写了一个小库,所有的操作都是async Task<T>,它是在一个单独的程序集,所以至少我们可以"正确"地在其他地方使用它(例如一个窗口电话应用程序),但是这个MVC 4项目是说库的消费者,感觉就像我们基本上是围绕async/await的好处,以避免死锁,所以我在这里寻找帮助。这将有助于更好地理解我通过在同步管理器中消费异步任务(如果有的话)获得了什么,我失去了什么,如果有一种解决方案可以让我回到没有死锁的情况下等待这些任务的能力,以及MVC 4和MVC 5+之间的情况是否不同

TIA

在Task.Run(() =>MyTask).结果,等待MyTask和MyTask.Result

在我的MVC4项目(目标。net 4.5.1)如果我等待SomeAsyncMethod(…),那么任务在后台完成,但似乎永远不会返回。

这几乎肯定是由于两个原因之一。:

  1. 调用堆栈上的代码在一个任务上调用ResultWait。这将导致ASP.NET中的死锁。正确的解决方案是将Result/Wait替换为await。我有更多的细节在我的博客。
  2. httpRuntime@targetFrameworkweb.config中没有设置为4.5或更高。这是ASP的常见场景。. NET项目从早期版本升级;您需要显式地设置此值才能使await正常工作。在这篇博文中有更多的细节。

所以,我发现自己不得不做Thread.Run(() => SomeAsyncMethod).Result;在我的MVC项目中大量使用,以免出现死锁。这难道不是同步运行任务的另一种语法吗?

差不多。实际发生的情况是,SomeAsyncMethod在线程池线程上运行,然后请求线程被阻塞,直到该方法完成。

这样做在异步性方面是否没有任何收获?

正确的。事实上,你的净收益是负的。

服务器端异步的全部意义在于通过在不需要的时候释放请求线程来提高可伸缩性。Task.Run(..).Result技术不仅防止释放请求线程,而且还使用其他线程来完成实际的工作。所以这比同步操作更糟糕

asp.net MVC 4应该知道Actions上的async关键字,并且应该在使用await关键字时正确处理恢复请求。您确定正在讨论的使用await的Action返回Task而不尝试返回T本身吗?

这是由asp.net MVC使用SynchronizationContext来处理的,以确保请求在等待后被正确地恢复,即使它在不同的线程上。

是的,如果你只是调用。result,它会阻塞调用线程,直到Task完成,你最终会使用(潜在的)两个线程来处理同一个请求,而没有任何好处。

http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4

除了@Stephen的回答,我的2美分:

我认为这与线程被返回到池中,然后在另一个线程上恢复有关。

编辑:

不,这一切都发生在单线程(通常是UI线程,在MVC的情况下,它的线程分配请求)。异步等待工作在消息泵,这是一个无限循环在单线程上运行。每个await都在消息泵上放置一条消息,并检查消息是否完成。

上面的

并不完全适用于Asp.net。请看下面@Jeff的评论

=========================================================

异步框架的一个规则,如果它是异步的,就一直保持异步

在Async方法上创建同步包装器通常会导致阻塞主线程,其中主线程和任务线程一直在等待对方的响应。