我正在创建ASP.NET Web API,其中某些操作(同步,遗留代码)可能需要一些时间(主要是IO限制,但也有一些计算密集型的东西)。
据我所知,每个传入的请求都被分配了一个来自线程池的线程,但我对其余部分有点模糊。请求线程是否以某种方式“特殊”,保证将工作卸载到其他线程以避免锁定它?卸载有助于线程池饥饿和被拒绝的请求吗?如果是这样,我是否需要为每个可能长时间运行的函数创建一个异步包装器,或者我是否只需要一个最高级别的异步包装器?
答案 0 :(得分:4)
为长时间运行的任务创建异步包装在ASP.NET上下文中毫无意义,除了以多种方式损害性能之外什么都不做。
在卸载GUI线程或其他特殊线程时,在线程池线程上异步运行同步方法是有意义的。在这种情况下,应该由调用者在该特殊线程上以调用者认为合适的方式异步调用该方法(使用例如Task.Run
,这通常不应该用于异步方法的实现)。然而,在ASP.NET中,只有线程池线程,并且由于多种原因,没有人需要(实际上不应该)以这种方式卸载。
最清楚的是Stephen Cleary(毕竟,他在C#中写了关于并发的书)Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation
这就是为什么ASP.NET的一个原则是避免使用线程池线程(当然,除了ASP.NET给你的请求线程)。更重要的是,这意味着 ASP.NET应用程序应该避免使用
Task.Run
。[...]
事实上,我们真正需要异步计算的唯一地方是我们从UI线程调用它。
强烈推荐整篇文章,并强调了在ASP.NET中卸载的各种问题。
进一步阅读: