我不确定我是否正确地问这个问题,所以请耐心等待;这就是我正在处理的事情:
在我的MVC4项目中(目标.Net 4.5.1)如果我await SomeAsyncMethod(...)
,那么任务在后台完成,但似乎永远不会返回。我相信这与线程返回到池然后在不同的线程上恢复有关。我一直在使用的解决方法是使用Thread.Run(() => SomeTask).Result;
。
所以,我发现自己必须在我的MVC项目中做Thread.Run(() => SomeAsyncMethod).Result;
以免我最终陷入僵局。这不是同步运行任务的另一种语法吗?我不确定这是否是MVC 4的限制(与MVC 5相比),或者这只是api的工作方式。通过这样做,我在异步性方面基本上没有获得任何东西吗?
我们在这里编写了一个小型库,其中所有操作都是async Task<T>
并且它位于一个单独的程序集中,所以至少我们可以在其他地方“正确”使用它(例如一个窗口电话应用程序),但是这个MVC 4项目是所述库的消费者,感觉就像我们基本上踩着async / await的好处以避免死锁,所以我正在寻找帮助来看到更大的图片。通过在同步管理器中消耗异步任务(如果有的话),我正在失去什么,如果有一个解决方案让我能够等待这些任务而没有死锁,以及是否或不是MVC 4和MVC 5 +之间的情况不同
TIA
答案 0 :(得分:3)
在我的MVC4项目中(目标.Net 4.5.1)如果我等待SomeAsyncMethod(...),那么任务在后台完成但似乎永远不会返回。
这几乎可以肯定是由于两件事之一。之一:
Result
或Wait
。这将导致ASP.NET中的死锁。正确的解决方案是将Result
/ Wait
替换为await
。我有更多详情on my blog。httpRuntime@targetFramework
中的4.5
未设置为web.config
或更高。这是从早期版本升级的ASP.NET项目的常见场景;您需要明确设置await
的此值才能正常工作。还有更多详情in this blog post。所以,我发现自己必须做Thread.Run(()=&gt; SomeAsyncMethod).Result;在我的MVC项目中有很多,以免我最终遇到死锁。这不是同步运行任务的另一种语法吗?
差不多。实际发生的是SomeAsyncMethod
在线程池线程上运行,然后阻塞请求线程,直到该方法完成。
通过这样做,我在异步性方面基本上没有获得任何东西吗?
正确。事实上,你正在消除负面利益。
服务器端的异步的全部要点是通过在不需要时释放请求线程来提高可伸缩性。 Task.Run(..).Result
技术不仅可以防止释放请求线程,还可以使用其他线程来完成实际工作。所以它比仅仅同步完成它更糟糕。
答案 1 :(得分:0)
除了@ Stephen的回答,我的2美分:
我认为这与返回池中的线程然后在不同的线程上恢复有关。
修改强>
不,这一切都发生在单个线程上(通常是UI线程,在MVC的情况下,它是为请求分配的线程)。异步等待消息泵工作,这是一个在单线程上运行的无限循环。每个await都会在消息泵上发送一条消息,并检查它是否已完成。
以上并不完全适用于Asp.net。请参阅下面的@ Jeff的评论。
=============================================== ==========
Async框架的一个规则,如果它是异步,请将其保持为异步。
通过Async方法创建同步包装器通常会导致阻塞主线程,其中主线程和任务线程一直等待彼此响应。
答案 2 :(得分:0)
ASP .NET MVC 4应该知道Actions上的async关键字,并且在使用await关键字时应该正确处理恢复请求。你确定使用await的有问题的Action会返回一个Task并且不会尝试返回T本身吗?
这是由ASP .NET MVC使用SynchronizationContext处理的,以确保请求在等待后正确恢复,即使它位于不同的线程上。
是的,如果你只是调用.Result,它会阻塞调用线程,直到任务完成,你最终使用(可能)两个线程来处理同一个请求而没有任何好处。
http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4