我有一个ConcurrentQueue
,其中填充了任意数量的对象,我想在不同的线程中处理这些对象。
如何等待所有排队的工作项完成?我见过的示例使用固定数组ManualResetEvents
,然后使用WaitHandle.WaitAll
来完成这些示例。
我是否需要管理线程数?我怎样才能继续排队,让ThreadPool处理多少运行?队列中将有数万个对象。
foreach (object A in myCollection)
{
ThreadPool.QueueUserWorkItem(A.process());
}
// now wait for all threads to finish
或者我是否必须跟踪列表中的所有ManualResetEvents,然后WaitAll以便所有人报告完成?
答案 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());