创建一个按键保留最新消息的数据流阻止

时间:2015-07-15 07:31:14

标签: c# .net task-parallel-library tpl-dataflow

我正在使用TPL Dataflow构建处理管道。我将物品送入管道,然后每个物品独立地移动通过管道,因为它从一个块到另一个块反弹,并最终在最后发出。这个管道实际上更像是一个网络,因为每个项目可以采用稍微不同的路径。

但是,在某些时候,我想在UI中显示每个项目的图形预览,当项目在管道中移动时,它应该自动更新。例如,想象这些物品是星舰,我想渲染每个星舰的盾牌和剩余的光子鱼雷的状态(是的,我最近一直在重新观看DS9)。例如,我的屏幕可能如下所示:

Defiant:    72% shields, 10 Quantum
Enterprise: 98% shields, 25 Photon

当然,盾牌和鱼雷可以独立耗尽,并且可能由于多种原因而发生。如果我有一个处理UI呈现的块,它将一直发送垃圾邮件,例如:

Defiant:    80% shields, 12 Quantum
Enterprise: 100% shields, 30 Photon
Defiant:    79% shields, 12 Quantum
Defiant:    79% shields, 11 Quantum
Defiant:    79% shields, 10 Quantum
Enterprise: 98% shields, 30 Photon
Enterprise: 98% shields, 29 Photon
...

我想做的是制作一个按照船名汇总所有这些消息的块。这样,当UI块选择消费消息时(相对很少会发生),它不会收到每艘船的整个作战历史记录,但只会收到最近的状态。

那么,编写像这样的块的最佳方法是什么?我写了一个快速而肮脏的版本,但我对此并不满意:

   public class KeyedBroadcastBlock<TKey, T> 
      : IPropagatorBlock<KeyValuePair<TKey, T>, KeyValuePair<TKey, T>>, IReceivableSourceBlock<KeyValuePair<TKey, T>>
   {
      private readonly IDictionary<TKey, T> itemsMap;
      ...    
      public KeyedBroadcastBlock()
      {
         itemsMap = new Dictionary<TKey, T>();
         inputBlock = new ActionBlock<KeyValuePair<TKey,T>>(
            kvp =>
            {
               lock (itemsMap) {
                  bool valueExists = itemsMap.ContainsKey(kvp.Key);
                  itemsMap[kvp.Key] = kvp.Value;
                  if (!valueExists) {
                     midBlock.Post(kvp.Key);
                  }
               }               
            });
         midBlock = new ActionBlock<TKey>(
            key =>
            {
               lock (itemsMap) {
                  T value;
                  if (itemsMap.TryGetValue(key, out value)) {
                     itemsMap.Remove(key);
                     outputBlock.Post(new KeyValuePair<TKey, T>(key, value));
                  }
               }
            });
         outputBlock = new BufferBlock<KeyValuePair<TKey, T>>();

         inputBlock.Completion.ContinueWith(delegate
            {
               midBlock.Complete();
               outputBlock.Complete();
            });
      }

      public bool TryReceive(Predicate<KeyValuePair<TKey, T>> filter, out KeyValuePair<TKey, T> item)
      {
         return outputBlock.TryReceive(filter, out item);
      }

      public bool TryReceiveAll(out IList<KeyValuePair<TKey, T>> items)
      {
         return outputBlock.TryReceiveAll(out items);
      }
   ...
   }

(编辑:为了演示目的清理了代码)

0 个答案:

没有答案