这里的其他答案似乎遗漏了最重要的一点:
除非您试图并行化CPU密集型操作以使其在低负载站点上更快地完成,否则根本没有必要使用辅助线程。
这适用于由创建的空闲线程new Thread(...)
和ThreadPool
响应QueueUserWorkItem
请求的中的工作线程。
是的,的确如此,您可以ThreadPool
通过排队太多的工作项来使ASP.NET进程挨饿。这将阻止ASP.NET处理进一步的请求。文章中的信息在这方面是准确的;用于相同的线程池QueueUserWorkItem
也用于处理请求。
但是,如果您实际上排队的工作项足以导致此饥饿,那么您应该使线程池处于饥饿状态!如果您实际上同时运行数百个CPU密集型操作,那么在计算机已经超载的情况下,让另一个工作线程服务ASP.NET请求有什么好处?如果遇到这种情况,则需要完全重新设计!
在大多数情况下,我看到或听到有关ASP.NET中不适当使用多线程代码的信息,这不是用于排队CPU密集型工作的。它用于排队I / O绑定的工作。并且,如果您要进行I / O工作,则应该使用I / O线程(I / O完成端口)。
具体来说,您应该使用所使用的任何库类支持的异步回调。这些方法总是非常清楚地标记;他们以Begin
和开头End
。如Stream.BeginRead
,Socket.BeginConnect
,WebRequest.BeginGetResponse
,等。
这些方法确实使用ThreadPool
,但是它们使用IOCP,它们不会干扰ASP.NET请求。它们是一种特殊的轻量级线程,可以被来自I / O系统的中断信号“唤醒”。在ASP.NET应用程序中,通常每个工作线程都有一个I / O线程,因此每个请求都可以排队一个异步操作。实际上,这是数百个异步操作,而性能没有任何显着下降(假设I / O子系统可以跟上)。它远远超出了您的需要。
请记住,异步委托不能以这种方式工作-他们最终将使用工作线程,就像ThreadPool.QueueUserWorkItem
。只有.NET Framework库类的内置异步方法能够执行此操作。您可以自己做,但是它很复杂且有点危险,可能超出了本讨论的范围。
我认为,对这个问题的最佳答案是不要在ASP.NET中使用ThreadPool
或后台Thread
实例。这根本不像在Windows Forms应用程序中扩展线程那样,您可以在其中执行此操作以保持UI响应能力,而不在乎它的效率。在ASP.NET中,您关心的是吞吐量,无论使用与否,所有这些工作线程上的所有上下文切换都绝对会杀死吞吐量ThreadPool
。
请,如果您发现自己在ASP.NET中编写线程代码-考虑是否可以使用预先存在的异步方法将其重写,如果不能,请考虑您是否真的需要该代码完全在后台线程中运行。在大多数情况下,您可能会添加复杂性而没有净收益。