线程池.QueueUserWorkItem中最大排队元素数

9

我将最大线程数设置为10。然后使用ThreadPool.QueueUserWorkItem添加了22000个任务。 运行程序后很可能并没有完成所有22000个任务。是否有任务数量限制可以排队等待可用线程?

4个回答

12

如果您需要等待所有任务处理完成,您需要自己处理。线程池线程都是后台线程,不会保持应用程序的活动状态。

以下是一种比较简洁的处理方法:

 using (var mre = new ManualResetEvent(false))
 {
      int remainingToProcess = workItems.Count(); // Assuming workItems is a collection of "tasks"
      foreach(var item in workItems)
      {
           // Delegate closure (in C# 4 and earlier) below will 
           // capture a reference to 'item', resulting in
           // the incorrect item sent to ProcessTask each iteration.  Use a local copy
           // of the 'item' variable instead.
           // C# 5/VS2012 will not require the local here.
           var localItem = item;
           ThreadPool.QueueUserWorkItem(delegate
           {
               // Replace this with your "work"
               ProcessTask(localItem);

               // This will (safely) decrement the remaining count, and allow the main thread to continue when we're done
               if (Interlocked.Decrement(ref remainingToProcess) == 0)
                      mre.Set();
           });
      }
      mre.WaitOne();
 }

话虽如此,如果你有成千上万个工作项,通常最好将它们“分组”,而不是将它们视为线程池中的单独工作项。管理项目列表涉及一些开销,而且由于你无法一次性处理22000个工作项,因此最好将它们分组为块。每个单一工作项处理50个左右可能会极大地提高你的整体吞吐量...


好主意,但应用程序正在等待所有线程。分组也是一个非常好的建议。 - Andras Csehi

7
队列没有实际限制,但池本身不会超过64个等待句柄,即活动线程的总数。

一个错误导致了我的问题,但基本上这个问题的答案就是这个。 - Andras Csehi
谢谢@keith。所以听起来队列大小的唯一真正限制是通用队列(或类似)对象本身的大小。 - C. Tewalt

4

ThreadPool文档中:

注意: 托管线程池中的线程是后台线程。也就是说,它们的IsBackground属性是true。这意味着,在所有前台线程退出后,ThreadPool线程将不会使应用程序继续运行。

你是否可能在所有任务被处理之前退出了?


4
这是一个与实现相关的问题,而这个函数的实现随着时间的推移有些变化。但是在.NET 4.0中,由于任务存储在内存队列中,您基本上受系统中可用内存量的限制。您可以通过在反编译器中查看其实现来了解此情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接