Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在高流量场景中使用ASP.NET中的ThreadPool.QueueUserWorkItem_Asp.net_Multithreading_Threadpool - Fatal编程技术网

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

在高流量场景中使用ASP.NET中的ThreadPool.QueueUserWorkItem,asp.net,multithreading,threadpool,Asp.net,Multithreading,Threadpool,我一直认为,即使在ASP.NET中,将线程池用于(比如说非关键的)短期后台任务也被认为是最佳实践,但后来我发现,这似乎是另一种建议——理由是您应该离开线程池来处理与ASP.NET相关的请求 到目前为止,我是如何完成小型异步任务的: ThreadPool.QueueUserWorkItem(s => PostLog(logEvent)) 而是建议显式创建一个线程,类似于: new Thread(() => PostLog(logEvent)){ IsBackground = true

我一直认为,即使在ASP.NET中,将线程池用于(比如说非关键的)短期后台任务也被认为是最佳实践,但后来我发现,这似乎是另一种建议——理由是您应该离开线程池来处理与ASP.NET相关的请求

到目前为止,我是如何完成小型异步任务的:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))
而是建议显式创建一个线程,类似于:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()
第一种方法的优点是可以被管理和绑定,但也有可能(如果本文是正确的话)后台任务会与ASP.NET请求处理程序争夺线程。第二种方法释放线程池,但代价是不受限制,因此可能会占用太多资源

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

如果你的站点流量过大,线程池已经满了,那么最好是跳出带宽,还是线程池满了就意味着你的资源已经到了极限,在这种情况下,你不应该尝试启动自己的线程


澄清:我只是在问一些小的非关键异步任务(例如,远程日志),而不是需要单独进程的昂贵工作项(在这些情况下,我同意您需要一个更健壮的解决方案)。

网站不应该到处繁殖线程

通常,您会将此功能移入Windows服务中,然后与之通信(我使用MSMQ与他们交谈)

--编辑

我在这里描述了一个实现:

--编辑

要详细说明这比线程更好的原因,请执行以下操作:

使用MSMQ,您可以与另一台服务器通信。您可以跨多台计算机写入队列,因此,如果出于某种原因确定后台任务占用主服务器的资源太多,您可以非常轻松地对其进行移动


它还允许您批处理您尝试执行的任何任务(发送电子邮件/任何任务)。

我肯定认为ASP.NET中快速、低优先级异步工作的一般做法是使用.NET线程池,特别是在高流量场景中,因为您希望资源受到限制

此外,线程的实现是隐藏的——如果您开始生成自己的线程,您还必须正确地管理它们。不是说你做不到,但为什么要重新发明那个轮子

如果性能成为一个问题,并且您可以确定线程池是限制因素(而不是数据库连接、传出网络连接、内存、页面超时等),那么您可以调整线程池配置以允许更多工作线程、更高的排队请求等

如果您没有性能问题,那么选择生成新线程以减少与ASP.NET请求队列的争用是典型的过早优化


理想情况下,您不需要使用单独的线程来执行日志记录操作—只需启用原始线程以尽快完成操作,这就是MSMQ和单独的使用者线程/进程的作用所在。我同意这是一项繁重的任务,需要执行更多的工作,但您确实需要在这里保持持久性—共享内存队列的波动性将很快耗尽它的受欢迎程度。

那篇文章不正确。ASP.NET有自己的线程池,即托管工作线程,用于服务ASP.NET请求。这个池通常有几百个线程,与ThreadPool池是分开的,ThreadPool池是处理器的较小倍数

在ASP.NET中使用线程池不会干扰ASP.NET工作线程。使用ThreadPool是可以的

也可以只设置一个线程来记录消息,并使用生产者/消费者模式将日志消息传递给该线程。在这种情况下,由于线程是长寿命的,因此应该创建一个新线程来运行日志记录

对每条消息使用一个新线程肯定是过分了


如果您只谈论日志记录,另一种选择是使用类似log4net的库。它在一个单独的线程中处理日志记录,并处理该场景中可能出现的所有上下文问题。

我认为这篇文章是错误的。如果您正在运行一个大型的.NET商店,您可以安全地跨多个应用程序和多个网站使用该池(使用单独的应用程序池),只需根据文档中的一句话:

每个进程有一个线程池。 线程池的默认大小为 每个可用线程250个工作线程 处理器和1000 I/O完成 线程。进程中的线程数 线程池可以通过使用 SetMaxThreads方法。每条线 使用默认堆栈大小并运行 以默认优先级


上周我在工作中被问到一个类似的问题,我会给你同样的答案。为什么每个请求都有多线程web应用程序?web服务器是一个非常棒的系统,经过大量优化,可以及时提供许多请求(即多线程)。想一想当你请求几乎任何网页时会发生什么

  • 对某个页面进行了请求
  • Html被发回
  • Html告诉客户端进行进一步的请求(js、css、图像等)
  • 进一步的信息将被发回
  • 您给出了远程日志记录的示例,但这应该是日志记录器关注的问题。应该有一个异步进程来及时接收消息。Sam甚至指出,您的记录器(log4net)应该已经支持这一点

    Sam也是正确的,因为在CLR上使用线程池不会导致IIS中的线程池出现问题。不过,这里需要注意的是,您不是从进程中派生线程,而是从进程中派生线程
    var ts = new CancellationTokenSource();
    CancellationToken ct = ts.Token;
    
    ParallelOptions po = new ParallelOptions();
                po.CancellationToken = ts.Token;
                po.MaxDegreeOfParallelism = 6; //limit here
    
     Task.Factory.StartNew(()=>
                    {                        
                      Parallel.ForEach(collectionList, po, (collectionItem) =>
                      {
                         //Code Here PostLog(logEvent);
                      }
                    });