注意:這是前一個問題的後續問題,我詢問here。處理單個工作項目集合的多個任務
只是爲了快速總結,我以前的問題是如何將WPF中的控件綁定到BlockingCollection
--這是通過使用CollectionViewSource解決的。
然而,我曾經想過我的用例多一點,並意識到,簡單地使用BlockingCollection
不會爲我工作。我想要以下行爲;
- 一「工作項目」的來源,提交給公共池
- 多,這些工作項目
- 項目目前仍在「等待」和那些被「處理」應的「處理器」兩個都出現在相同的數據綁定視圖。
例如;
8個工作項目被同時提交,和併發的最高水平4.工作項目的四應該被移動到「處理中」狀態,而其他四個停留在「待定」。隨着「處理」狀態中的每個項目完成,將從「待處理」狀態中選取另一項目進行處理。一旦項目完成處理,它將從工作項目池中移除。這對用戶是實時可見的。
我之前採用的方法存在的問題是,當一件物品被拿起來處理時,它會從視圖中消失,因爲它被GetConsumingEnumerable
的調用「消耗」了。我真正想要的是對項目安全地挑出來進行處理「待定」池,但仍留在視圖中,這樣的狀態更新(通過INotifyPropertyChanged
)可能在UI中可見。
我已經解決(我結合的,而不是使用ICollectionView
)
我已經實現本項實際使用兩個並行集合而不是,然後包裹起來作爲單個CompositeCollection從視圖消失的問題行爲如下;
this.currentWorkItems = new ObservableConcurrentCollection<WorkItem>();
this.pendingWorkItems = new ObservableConcurrentCollection<WorkItem>();
this.compositeCollection = new CompositeCollection
{
new CollectionContainer { Collection = this.currentWorkItems},
new CollectionContainer { Collection = this.pendingWorkItems },
};
for (int i = 0; i < workConcurrencyFactor; i++)
{
Task.Factory.StartNew(this.ProcessWorkItems);
}
然後我的Add
方法;
public void Add(WorkItem workItem)
{
this.pendingWorkItems.TryAdd(workItem);
}
最後,ProcessWorkItems
方法;
private void ProcessWorkItems()
{
while (true)
{
Thread.Sleep(100);
WorkItem workItem;
if (this.pendingWorkItems.TryTake(out workItem))
{
this.currentWorkItems.TryAdd(workItem);
workItem.Status = "Simulating First Step";
Thread.Sleep(1000);
workItem.Status = "Simulating Second Step";
Thread.Sleep(1000);
// Finished processing
this.currentWorkItems.TryTake(out workItem);
}
}
}
注意,我使用ObservableConcurrentCollection
從here。
這工作不錯,但我覺得我在這裏的東西,或者說,我可能通過具有多任務的睡眠和覺醒不斷在沒有其他真的發生被招致完全不必要的開銷。另外,我覺得我濫用了第二ObservableConcurrentCollection
一些,通過實質上只是用它作爲該我工作的一個項目持有面積,但我還是想可見。
是否有這個問題更好的方法?併發消費者採用「就地」方式處理集合的標準模式是什麼,同時避免多個消費者攫取同一物品?
這聽起來像在[TPL數據流(http://msdn.microsoft的範圍問題。 com/en-us/library/hh228603%28v = vs.110%29.aspx)域。如果我是你,我會仔細研究它是否有幫助。數據流管道將執行處理,而所有項目都將位於綁定集合中以查看更新(?)。 –
感謝您的建議,我現在就研究一下。 –