2014-04-18 56 views
0

注意:這是前一個問題的後續問題,我詢問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); 
     } 
    } 
} 

注意,我使用ObservableConcurrentCollectionhere

這工作不錯,但我覺得我在這裏的東西,或者說,我可能通過具有多任務的睡眠和覺醒不斷在沒有其他真的發生被招致完全不必要的開銷。另外,我覺得我濫用了第二ObservableConcurrentCollection一些,通過實質上只是用它作爲該我工作的一個項目持有面積,但我還是想可見。

是否有這個問題更好的方法?併發消費者採用「就地」方式處理集合的標準模式是什麼,同時避免多個消費者攫取同一物品?

+1

這聽起來像在[TPL數據流(http://msdn.microsoft的範圍問題。 com/en-us/library/hh228603%28v = vs.110%29.aspx)域。如果我是你,我會仔細研究它是否有幫助。數據流管道將執行處理,而所有項目都將位於綁定集合中以查看更新(?)。 –

+0

感謝您的建議,我現在就研究一下。 –

回答

1

由於Patryk已經建議這是TPL Dataflow一個很好的例子 - 我們做類似(只是在流水線的幾個步驟,包括配料和轉換)的東西在這裏:

創建您的數據流塊來處理任務和集合持有所有的人:

var actionBlock = new ActionBlock<WorkItem>(item => ProcessWorkItem(item), 
    new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = threadCount }); 
var allItems = new ConcurrentDictionary<int, WorkItem>(); // or whatever fits 

然後在該Add方法:

public void Add(WorkItem workItem) 
{ 
    allItems.Add(workItem.Id, workItem); 
    actionBlock.Post(workItem); 
} 

而在ProcessWorkItem末做allItems.Remove(workItem.Id)

PS:數據流塊是相當快的也 - 我們做每秒這裏幾百Post電話......

+0

不錯的例子,歡呼聲。我已經使用這個實現了一個原型,它已經嚴重減少了我的視圖模型中的代碼量。再加上它看起來非常快 - 偉大的東西。 –

+0

只是跟進..我忘了提,我的應用程序的目標是.NET4.0,我沒有範圍升級到4.5。你可以想像我的反應,當我意識到有數據流的4.0沒有穩定的發佈:-)我又回到了兩個併發字典原來的想法,但增加額外的「票號」的ConcurrentQueue ,這是使用對字典進行類似隊列的處理。性能仍然非常好,但可能比DataFlow實現慢25% - 這對我的使用情況來說是可以忍受的。再次感謝您的建議,我會再次使用DF! –

+1

也許這會有所幫助:http://stackoverflow.com/questions/15338907/where-can-i-find-a-tpl-dataflow-version-for-4-0 – ChrFin