在高流量场景中使用 ASP.NET 中的 ThreadPool.QueueUserWorkItem [英] Using ThreadPool.QueueUserWorkItem in ASP.NET in a high traffic scenario

查看:26
本文介绍了在高流量场景中使用 ASP.NET 中的 ThreadPool.QueueUserWorkItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直认为,即使在 ASP.NET 中,将 ThreadPool 用于(假设是非关键的)短期后台任务也被认为是最佳实践,但后来我遇到了 这篇文章 似乎另有建议 - 论点是您应该离开 ThreadPool 来处理 ASP.NET相关请求.

I've always been under the impression that using the ThreadPool for (let's say non-critical) short-lived background tasks was considered best practice, even in ASP.NET, but then I came across this article that seems to suggest otherwise - the argument being that you should leave the ThreadPool to deal with ASP.NET related requests.

到目前为止,我是这样处理小型异步任务的:

So here's how I've been doing small asynchronous tasks so far:

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

文章建议改为显式创建线程,类似于:

And the article is suggesting instead to create a thread explicitly, similar to:

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

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

The first method has the advantage of being managed and bounded, but there's the potential (if the article is correct) that the background tasks are then vying for threads with ASP.NET request-handlers. The second method frees up the ThreadPool, but at the cost of being unbounded and thus potentially using up too many resources.

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

So my question is, is the advice in the article correct?

如果您的网站获得了如此多的流量,以至于您的 ThreadPool 已满,那么是带外使用更好,还是完整的 ThreadPool 意味着您无论如何都达到了资源的限制,在在哪种情况下您不应该尝试启动自己的线程?

If your site was getting so much traffic that your ThreadPool was getting full, then is it better to go out-of-band, or would a full ThreadPool imply that you're getting to the limit of your resources anyway, in which case you shouldn't be trying to start your own threads?

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

Clarification: I'm just asking in the scope of small non-critical asynchronous tasks (eg, remote logging), not expensive work items that would require a separate process (in these cases I agree you'll need a more robust solution).

推荐答案

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

Other answers here seem to be leaving out the most important point:

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

这适用于由 new Thread(...) 创建的空闲线程,以及响应 QueueUserWorkItemThreadPool 中的工作线程> 请求.

That goes for both free threads, created by new Thread(...), and worker threads in the ThreadPool that respond to QueueUserWorkItem requests.

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

Yes, it's true, you can starve the ThreadPool in an ASP.NET process by queuing too many work items. It will prevent ASP.NET from processing further requests. The information in the article is accurate in that respect; the same thread pool used for QueueUserWorkItem is also used to serve requests.

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

But if you are actually queuing enough work items to cause this starvation, then you should be starving the thread pool! If you are running literally hundreds of CPU-intensive operations at the same time, what good would it do to have another worker thread to serve an ASP.NET request, when the machine is already overloaded? If you're running into this situation, you need to redesign completely!

大多数时候,我看到或听说多线程代码在 ASP.NET 中被不当使用,这并不是为了排队 CPU 密集型工作.它用于排队 I/O 绑定的工作.如果你想做 I/O 工作,那么你应该使用 I/O 线程(I/O 完成端口).

Most of the time I see or hear about multi-threaded code being inappropriately used in ASP.NET, it's not for queuing CPU-intensive work. It's for queuing I/O-bound work. And if you want to do I/O work, then you should be using an I/O thread (I/O Completion Port).

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

Specifically, you should be using the async callbacks supported by whatever library class you're using. These methods are always very clearly labeled; they start with the words Begin and End. As in Stream.BeginRead, Socket.BeginConnect, WebRequest.BeginGetResponse, and so on.

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

These methods do use the ThreadPool, but they use IOCPs, which do not interfere with ASP.NET requests. They are a special kind of lightweight thread that can be "woken up" by an interrupt signal from the I/O system. And in an ASP.NET application, you normally have one I/O thread for each worker thread, so every single request can have one async operation queued up. That's literally hundreds of async operations without any significant performance degradation (assuming the I/O subsystem can keep up). It's way more than you'll ever need.

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

Just keep in mind that async delegates do not work this way - they'll end up using a worker thread, just like ThreadPool.QueueUserWorkItem. It's only the built-in async methods of the .NET Framework library classes that are capable of doing this. You can do it yourself, but it's complicated and a little bit dangerous and probably beyond the scope of this discussion.

在我看来,这个问题的最佳答案是不要使用 ThreadPool 后台 Thread 实例在 ASP.NET 中.这根本不像在 Windows 窗体应用程序中启动线程,您这样做是为了保持 UI 响应并且不关心它的效率.在 ASP.NET 中,您关心的是吞吐量,并且所有这些工作线程上的所有上下文切换绝对会杀死您的吞吐量,无论您是否使用 ThreadPool 与否.

The best answer to this question, in my opinion, is don't use the ThreadPool or a background Thread instance in ASP.NET. It's not at all like spinning up a thread in a Windows Forms application, where you do it to keep the UI responsive and don't care about how efficient it is. In ASP.NET, your concern is throughput, and all that context switching on all those worker threads is absolutely going to kill your throughput whether you use the ThreadPool or not.

如果您发现自己在 ASP.NET 中编写线程代码 - 请考虑是否可以将其重写为使用预先存在的异步方法,如果不能,请考虑您是否真的,真的需要代码在后台线程中运行.在大多数情况下,您可能会在没有任何净收益的情况下增加复杂性.

Please, if you find yourself writing threading code in ASP.NET - consider whether or not it could be rewritten to use pre-existing asynchronous methods, and if it can't, then please consider whether or not you really, truly need the code to run in a background thread at all. In the majority of cases, you will probably be adding complexity for no net benefit.

这篇关于在高流量场景中使用 ASP.NET 中的 ThreadPool.QueueUserWorkItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆