C# 具有任意线程数的ThreadPool.QueueUserWorkItem

C# 具有任意线程数的ThreadPool.QueueUserWorkItem,c#,multithreading,C#,Multithreading,我有一个ConcurrentQueue,其中填充了任意数量的对象,我希望在单独的线程中处理这些对象 如何等待所有排队的工作项完成?我看到的示例使用了一个固定的ManualResetEvents数组,然后使用WaitHandle.WaitAll来完成它们 var finished = new CountdownEvent(1); foreach (object A in myCollection) { var capture = A; // Required to close over th

我有一个
ConcurrentQueue
,其中填充了任意数量的对象,我希望在单独的线程中处理这些对象

如何等待所有排队的工作项完成?我看到的示例使用了一个固定的
ManualResetEvents
数组,然后使用
WaitHandle.WaitAll
来完成它们

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
我需要管理线程的数量吗?我怎样才能让线程池处理有多少线程正在运行呢?队列中将有数万个对象

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

或者我必须跟踪列表中的所有手动重置事件,然后等待所有事件报告完成吗?

您不应该将工作项排队,而应该使用任务库(System.Threading.tasks),它为您提供了更多的功能,包括可重放调度程序。

您不应该对工作项排队,而应该使用任务库(System.Threading.tasks),它为您提供了更多功能,包括可重放调度程序。

如何(从4.0开始):

(从4.0开始)怎么样


使用
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

但是,如果您决定使用任务并行库,则有不同的方法来完成相同的基本任务。

使用
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

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

对不起,我可能过度简化了我的示例。Parallel.ForEach不起作用,因为集合是一个队列,随着循环的滚动,它将发生变化。@Cylindric小心这一点;目前,您的
foreach
可能在任何
ThreadPool
线程启动之前很久就完成了;意思是:
process()
不会有任何额外的副作用yet@Cylindric在这种情况下,您能否
while(myCollection.Count>0)Parallel.ForEach(myCollection,a=>a.process())?对不起,我可能过度简化了我的示例。Parallel.ForEach不起作用,因为集合是一个队列,随着循环的滚动,它将发生变化。@Cylindric小心这一点;目前,您的
foreach
可能在任何
ThreadPool
线程启动之前很久就完成了;意思是:
process()
不会有任何额外的副作用yet@Cylindric在这种情况下,您能否
while(myCollection.Count>0)Parallel.ForEach(myCollection,a=>a.process())?好的,Task 1Library看起来非常适合这个。好的,Task 1Library看起来非常适合这个。我最后选择了Task方法,但是感谢关于CountdownEvent的信息-我以前没有遇到过。我最后选择了Task方法,但是感谢关于CountdownEvent的信息-我以前没有遇到过。