ThreadPool.QueueUserWorkItem具有任意数量的线程

时间:2011-11-29 13:50:29

标签: c# multithreading

我有一个ConcurrentQueue,其中填充了任意数量的对象,我想在不同的线程中处理这些对象。

如何等待所有排队的工作项完成?我见过的示例使用固定数组ManualResetEvents,然后使用WaitHandle.WaitAll来完成这些示例。

我是否需要管理线程数?我怎样才能继续排队,让ThreadPool处理多少运行?队列中将有数万个对象。

foreach (object A in myCollection)
{
    ThreadPool.QueueUserWorkItem(A.process());
}
// now wait for all threads to finish

或者我是否必须跟踪列表中的所有ManualResetEvents,然后WaitAll以便所有人报告完成?

3 个答案:

答案 0 :(得分:2)

您不应该对工作项进行排队,而是使用任务库(System.Threading.Tasks),它为您提供了更多功能,包括可替换的调度程序。

答案 1 :(得分:2)

使用WaitHandle.WaitAll不是一个非常可扩展的解决方案,因为它有64个句柄限制。

使用QueueUserWorkItem时执行此操作的规范方法是使用CountdownEvent。为每个工作项添加计数,并在工作项完成时发出信号。在下面的示例中,您将注意到我将主线程视为工作项,以防止在工作项完成时可能发生的非常微妙的竞争条件,并在排队完成之前发出事件信号。

var finished = new CountdownEvent(1);
foreach (object A in myCollection) 
{
  var capture = A; // Required to close over the loop variable 
  finished.AddCount(); // Indicate that there is another work item
  ThreadPool.QueueUserWorkItem(
    (state) =>
    {
      try
      {
        capture.process();
      }
      finally
      {
        finished.Signal(); // Signal work item is complete
      }
    }, null);
} 
finished.Signal(); // Signal queueing is complete
finished.Wait(); // Wait for all work items

如果您决定使用任务并行库,则有不同的方法可以完成相同的基本操作。

答案 2 :(得分:1)

如何(从4.0开始):

Parallel.ForEach(myCollection, a => a.process());