我有一个ASP MVC调用,由于需要进行异步调用,因此它是异步的。我注意到有几个慢同步调用(例如数据库访问)。该方法需要所有返回的数据都可用才能继续。
我考虑使用Task.Run将同步调用包装起来,并等待它们全部完成。
将慢同步调用包装起来是否有意义?如果只有同步调用会怎样?
我考虑使用Task.Run将同步调用包装起来,并等待它们全部完成。
将慢同步调用包装起来是否有意义?如果只有同步调用会怎样?
除非您预计要同时服务的客户端请求数量非常低,否则不要在服务器端代码中使用Task.Run
并行化工作。否则,您可能会加速单个请求的处理,但当有许多用户时,这将损害 Web 应用程序的可扩展性。
试图通过启动线程来“加速”同步工作的尝试并不能很好地扩展@Noseratio。
需要记住的一件重要事情是,在ASP.NET中使用Task.Run
非常危险,因为运行时不知道您排队等待完成的工作,IIS可能会定期尝试回收您的应用程序,这将导致工作意外中止。
如果您正在使用.NET Framework 4.5.2,则可以通过HostingEnvironment.QueueBackgroundWorkItem
解决此问题。您可以在ASP.NET上的Fire and Forget
中了解更多信息。如果没有,请阅读从ASP.NET请求中提前返回
以获取自定义实现。这两篇优秀文章都是由@StephanCleary撰写的。
async
Web API方法内部第一次遇到await
时,主要的操作线程(HTTP请求最初着陆以进行处理的线程)将被释放。但是,在此时请求仍处于挂起状态(因为await
),因此IIS进程/应用程序域不会被回收。在内部,跟踪是通过AsyncManager
完成的。但是,在ASP.NET中,像await Task.Run(DoWork)
这样的事情是没有意义的:它只会释放一个线程并获取另一个线程。 - noseratio - open to work
Task.Run
,则不会释放线程。至于包装单个同步调用,根本没有意义-您可能会在当前线程上执行它。至于并行包装多个调用-您会损害可扩展性。 - noseratio - open to workTask.Run
)消耗并阻塞池线程可能会对可伸缩性产生非常严重的影响。还有臭名昭著的ThreadPool口吃行为需要记在心里,这里有一篇相关帖子附有一些研究资料。毕竟,为什么要通过使用Task.Run
分叉阻塞调用来加速单个客户端的请求处理,而让其他客户端因没有空闲池线程而等待呢? - noseratio - open to work