2016-03-08 59 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 
    } 

我会离开使得多线程作为一个练习留给读者。