[英]Producer/Consumer, BlockingCollection, and waiting for changes
我试图围绕BlockingCollection和生产者/消费者问题进行讨论。
我要实现的目标如下:
换一种说法:
Inbound "Job" Data, can come at any time from multiple threads
==> Thread-Safe FIFO Queue 1 "FQ1"
==> Async Processing of data in FQ1 (and remove item from FQ1)
==> Callback/Results into Thread-Safe FIFO Queue 2 "FQ2"
==> Async Processing of data in FQ2 (and remove item from FQ2)
==> Done
到目前为止,我的拙劣尝试是:
private BlockingCollection<InboundObject> fq1;
private BlockingCollection<ResultObject> fq2;
(...)
Task.Factory.StartNew(() =>
{
foreach (InboundObject a in fq1.GetConsumingEnumerable())
a.DoWork(result => fq2.Add(result)); //a.DoWork spits out an Action<ResultObject>
}
我选择BlockingCollection的原因之一是因为我希望将负载保持在最低水平,这意味着仅当项目实际上在集合中时才起作用(而不处理等待/睡眠)。 我不确定foreach是否是正确的方法。
请让我知道这是否正确或是否有更好的方法。 谢谢!
编辑我可以从单元测试中看出,任务内部的工作实际上是同步的。 新版本如下:
Task.Factory.StartNew(() =>
{
foreach (InboundObject a in fq1.GetConsumingEnumerable())
Task.Factory.StartNew(async () => { fq2.Add(await a.DoWork()); });
}
输入非常感谢!
我选择BlockingCollection的原因之一是因为我希望将负载保持在最低水平,这意味着仅当项目实际上在集合中时才起作用(而不处理等待/睡眠)。 我不确定foreach是否是正确的方法。
这是正确的方法,在将新项目添加到队列中或将调用CompleteAdding
方法之前, foreach
将被阻止。 不正确的是您想使用BlockingCollection实现异步处理。 BlockingCollection是一个简单的生产者/消费者队列,需要维护作业和作业结果的顺序时必须使用BlockingCollection。 因此,它是同步的。 作业将按照添加时的相同顺序进行处理。
如果您需要的只是异步执行,则不需要队列。 在这种情况下,您可以使用TPL,只需为每个作业生成一个新任务,它们就会由TPL在内部排队,并且将使用系统可以有效处理的尽可能多的OS线程。 例如,您的工作可以产生自己的任务。 这是更加灵活的方法。
同样,生产者/消费者队列可用于组织作业的管道执行。 在这种情况下,必须将作业分为几个步骤。 每个步骤必须由专用线程执行。 在每个作业步骤线程中,我们必须从一个队列中读取作业,执行该作业,然后将其排队进入下一个队列。
interface IJob
{
void Step1();
void Step2();
...
}
var step1 = new BlockingCollection<IJob>();
var step2 = new BlockingCollection<IJob>();
...
Task.Factory.StartNew(() =>
{
foreach(var step in step1.GetConsumingEnumerable()) {
step.Step1();
step2.Add(step);
}
});
Task.Factory.StartNew(() =>
{
foreach(var step in step2.GetConsumingEnumerable()) {
// while performing Step2, another thread can execute Step1
// of the next job
step.Step2();
step3.Add(step);
}
});
在这种情况下,作业将以FIFO顺序但并行执行。 但是,如果要进行管道处理,则必须首先考虑负载平衡。 如果其中一个步骤花费了太多时间,则它的队列将变大,而其他线程在大多数情况下将处于空闲状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.