asp.net - 在高流量场景中使用 ASP.NET 中的 ThreadPool.QueueUserWorkItem

标签 asp.net multithreading threadpool

我一直认为,即使在 ASP.NET 中,使用 ThreadPool 执行(比方说非关键的)短期后台任务也被认为是最佳实践,但后来我遇到了 this article这似乎表明并非如此 - 论点是您应该让 ThreadPool 来处理 ASP.NET 相关请求。

以下是迄今为止我执行小型异步任务的方式:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

the article建议改为显式创建线程,类似于:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

第一种方法具有受管理和有界的优点,但后台任务有可能(如果文章正确的话)与 ASP.NET 请求处理程序争夺线程。第二种方法释放了ThreadPool,但代价是不受限制,因此可能会占用太多资源。

所以我的问题是,文章中的建议正确吗?

如果您的网站流量如此之大,以至于您的线程池已满,那么最好采用带外方式,还是满的线程池意味着您无论如何都已达到资源限制,在在哪种情况下您不应该尝试启动自己的线程?

澄清:我只是在小型非关键异步任务(例如远程日志记录)的范围内询问,而不是需要单独流程的昂贵工作项目(在这些情况下,我同意您需要一个更强大的工具)解决方案)。

最佳答案

这里的其他答案似乎遗漏了最重要的一点:

除非您尝试并行化 CPU 密集型操作以便在低负载站点上更快地完成该操作,否则使用工作线程根本没有意义。

这适用于由 new Thread(...) 创建的自由线程,以及 ThreadPool 中响应 QueueUserWorkItem 的工作线程> 请求。

是的,确实如此,您可以通过对太多工作项进行排队来使 ASP.NET 进程中的 ThreadPool 挨饿。它将阻止 ASP.NET 处理进一步的请求。文章中的信息在这方面是准确的;用于QueueUserWorkItem的相同线程池也用于服务请求。

但是,如果您实际上排队的工作项足以导致这种饥饿,那么您应该导致线程池饥饿!如果您同时运行数百个 CPU 密集型操作,那么当计算机已经过载时,使用另一个工作线程来处理 ASP.NET 请求有什么好处呢?如果您遇到这种情况,则需要完全重新设计!

大多数时候,我看到或听到有关 ASP.NET 中不恰当使用多线程代码的情况,它并不是为了对 CPU 密集型工作进行排队。它用于对 I/O 密集型工作进行排队。 如果您想要执行 I/O 工作,那么您应该使用 I/O 线程(I/O 完成端口)。

具体来说,您应该使用您正在使用的任何库类支持的异步回调。这些方法总是有非常清晰的标签;它们以 BeginEnd 一词开头。如 Stream.BeginReadSocket.BeginConnectWebRequest.BeginGetResponse 等。

这些方法确实使用ThreadPool,但它们使用IOCP,而IOCP不会干扰 ASP.NET 请求。它们是一种特殊的轻量级线程,可以被来自 I/O 系统的中断信号“唤醒”。在 ASP.NET 应用程序中,通常每个工作线程都有一个 I/O 线程,因此每个请求都可以有一个排队的异步操作。这实际上是数百个异步操作,而没有任何显着的性能下降(假设 I/O 子系统可以跟上)。这远远超出您的需要。

请记住,异步委托(delegate)不会以这种方式工作 - 它们最终会使用工作线程,就像ThreadPool.QueueUserWorkItem一样。只有 .NET Framework 库类的内置异步方法才能够执行此操作。您可以自己做,但它很复杂,而且有点危险,可能超出了本讨论的范围。

在我看来,这个问题的最佳答案是不要使用ThreadPool后台Thread实例在 ASP.NET 中。它与在 Windows 窗体应用程序中旋转线程完全不同,在 Windows 窗体应用程序中,您这样做是为了保持 UI 响应,而不关心它的效率如何。在 ASP.NET 中,您关心的是吞吐量,无论您是否使用 ThreadPool<,所有这些工作线程上的所有上下文切换都绝对会杀死您的吞吐量 或不。

如果您发现自己在 ASP.NET 中编写线程代码,请考虑是否可以重写它以使用预先存在的异步方法,如果不能,请考虑您是否真的非常真正地根本需要代码在后台线程中运行。在大多数情况下,您可能会增加复杂性而没有任何净 yield 。

关于asp.net - 在高流量场景中使用 ASP.NET 中的 ThreadPool.QueueUserWorkItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1325718/

相关文章:

java - 带有执行器框架的可调用接口(interface)。为什么即使从调用方法返回后程序也没有退出

c# - 使用 ImageGen 时出现类型或 namespace 错误

ASP.Net 5 RC2 配置节绑定(bind)

android - Android SQLiteDatabase 线程安全吗?

java - 队列中的多线程作业 - 作业太多?

ejb - 如何解决 - JBAS014516 : Failed to acquire a permit within 5 MINUTES

asp.net - IIS 应用程序池标识以使用登录用户 Windows 标识

c# - 使用 ASP.Net Core 定位 net core 应用程序和完整的 net461

C# 多线程和套接字问题

python - 使用外部命令多重处理数千个文件