等待阻塞集合(队列)在C#中减小

时间:2013-03-06 17:01:22

标签: c# .net multithreading queue event-driven

我正在使用以下工作流程开展项目:

第一部分:

  • 事件异步到达并在阻塞队列中排队,我们称之为 Q1
  • 线程从该队列中选取下一个可用项目
  • 项目最终并行运行{N}个任务数
  • 每个任务将结果排在第二个队列中,我们称之为 Q2
  • 当项目处理完成时,将从队列中读取下一个项目。

第二部分:

  • 另一个帖子一次读取 Q2 一个对象并处理结果

因此,问题在于,第一个队列中的每个项目最终并行运行大量任务,每个任务将其结果排队。第二个队列必须按顺序处理,一次一个项目,然后它就会被淹没。


我的问题

我需要一种机制,让线程处理 Q1 等到 Q2 中的项目数低于特定阈值。实现这一目标的最佳方法是什么?有没有办法让事件驱动的解决方案而不是轮询解决方案?

3 个答案:

答案 0 :(得分:8)

您可以使用BlockingCollection<T>作为Q2,而不是使用Queue<T>。如果您设置了BoundedCapacity,则会在达到容量时阻止对Q2.Add()的呼叫。这将自动限制Q1的处理,因为如果N个任务无法添加到最终队列,它们将开始阻塞。

答案 1 :(得分:2)

我假设您在偶尔的洪水中接收数据,长期干旱可以赶上Q2。您是否考虑过通过使用有限的线程池来限制从Q1生成的并发线程数?

如果在到达时很容易确定作业大小,我怀疑您可以从多个线程池中受益。您可以使用少量线程来处理大型作业,并且可以使用大量线程来处理小型作业。即使是第三个中间队列也可能是有益的。

答案 2 :(得分:1)

您的问题似乎是TPL Dataflow库要解决的完美示例。如果您愿意尝试,可以使用它(当然这是一个非常简单的例子):

TransformBlock<int, bool> transform = new TransformBlock<int, bool>(i => i > 5 ? true : false,
            new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });
ActionBlock<bool> resultBlock = new ActionBlock<bool>(b => Console.WriteLine("My result is : " + b),
            new ExecutionDataflowBlockOptions { BoundedCapacity = 10 });
transform.LinkTo(resultBlock);

您正在定义一个转换块,它将进行转换(这可以作为您的Q1),您可以将它的并行度设置为您想要使用的任务数。

然后,您正在创建第二个块(作为您的Q2),它将设置BoundedCapacity并且它正在同步处理每个消息,为每个元素调用一个动作。此块可以被任何其他块替换,例如BufferBlock,允许您根据需要从中进行轮询。