我正在使用以下工作流程开展项目:
第一部分:
第二部分:
因此,问题在于,第一个队列中的每个项目最终并行运行大量任务,每个任务将其结果排队。第二个队列必须按顺序处理,一次一个项目,然后它就会被淹没。
我的问题
我需要一种机制,让线程处理 Q1 等到 Q2 中的项目数低于特定阈值。实现这一目标的最佳方法是什么?有没有办法让事件驱动的解决方案而不是轮询解决方案?
答案 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
,允许您根据需要从中进行轮询。