2016-03-08 91 views
0

假設我有一個BlockingCollection隊列,我加入了以下事件:如何實現隊列混爲一談

A - > B1 - 「ç - > B2 - > B1

我基本上只關心最後B1事件。我想在這種情況下能夠放棄其他B1的前面(但仍處理B2,因爲它使用的是不同於B1的ID值)。這似乎與BlockingCollection我不能實現這一點,除非我可以控制每次添加B1或B2時,我不知道何時會添加另一個B.

我想過創建一個包含B事件的單獨數據結構(它將是一個ConcurrentDictionary,其中鍵類型是一個ID值 - 如果具有相同ID值的2個B事件一個接一個地被添加,而不是第一個一個會被丟棄,因爲它會被字典覆蓋)。這個問題是我失去了所有重要事件的順序。我仍然希望以上面顯示的順序處理事件。

任何想法?

+0

你需要先進先出嗎? – Robert

+0

是的,我需要先進先出。 – Andrew

+0

如果您只希望執行最後一個B1事件,您是否願意承擔從未處理過的B1事件?你想如何處理B1事件會不斷推回的可能性? – Robert

回答

0

根據您的意見,這裏有幾個選項:

  • 實現櫃檯或標誌等,只有B項類型的單個實例可以在隊列中存在。
  • 設置「B事件」字典,以便您的密鑰是B事件的ID,並且該值是對相應隊列節點的引用。如果新的B事件進入隊列,請在字典中查找。如果已經存在這種類型,只需用新的B事件換出新的隊列節點,或者直接將節點的引用指向新的B事件實例。由於您只更改屬於舊B事件實例的隊列節點,因此不會丟失其他項目的排序。
1
class ConflatingQueue<TKey, TValue> : IEnumerable<TValue> 
{ 
    private readonly Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>(); 
    private readonly Queue<TKey> keys = new Queue<TKey>(); 

    public void Enqueue(TKey key, TValue value) 
    { 
     if (dict.ContainsKey(key)) 
     { 
      dict[key] = value; 
     } 
     else 
     { 
      dict.Add(key, value); 
      keys.Enqueue(key); 
     } 
    } 

    public TValue Dequeue() 
    { 
     var key = keys.Dequeue(); 
     var value = dict[key]; 
     dict.Remove(key); 
     return value; 
    } 

    public IEnumerator<TValue> GetEnumerator() 
    { 
     foreach (var key in keys) 
     { 
      yield return dict[key]; 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

哪位能像這樣被使用:

public static void Main(string[] args) 
    { 
     //A -> B1 -> C -> B2 -> B1 
     var cq = new ConflatingQueue<string, string>(); 
     cq.Enqueue("A", "A"); 
     cq.Enqueue("B1", "B1"); 
     cq.Enqueue("C", "C"); 
     cq.Enqueue("B2", "B2"); 
     cq.Enqueue("B1", "B1"); 

     Console.WriteLine(string.Join(",", cq)); //A,B1,C,B2 
    } 

我會離開使得多線程作爲一個練習留給讀者。