[英]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.