我最近开始使用.NET 4.5中的TPL Dataflow库,整个块的概念对我来说都是新的。我正在我的应用程序中实现生产者 - 消费者队列,我需要防止重复的消息被放入队列,因此需要检查消息是否已经排队。我使用的是BufferBlock<Message>
类型(Message
是自定义类型)。 BufferBlock
具有Count属性,但在此问题中没有帮助,因为需要唯一标识消息。
有没有办法检查BufferBlock
是否包含某个项目,或者检查所有项目并进行检查?是否可以将BufferBlock
转换为允许迭代项目的内容?我正在关注example I saw on MSDN并且它不会检查项目是否在队列中,但我认为检查队列的内容是一项非常需要的操作。任何帮助表示赞赏。
答案 0 :(得分:5)
为什么不将BufferBlock
插入到为您执行此操作的链中,而不是闯入TransformManyBlock
?您可以使用HashSet
,Add
方法仅在尚未添加项目的情况下返回true
。它最终变得非常简单,但存储需求明显随着时间而增加......
void Main()
{
var bb = new BufferBlock<string>();
var db = DataflowEx.CreateDistinctBlock<string>();
var ab = new ActionBlock<string>(x => Console.WriteLine(x));
bb.LinkTo(db);
db.LinkTo(ab);
bb.Post("this");
bb.Post("this");
bb.Post("this");
bb.Post("is");
bb.Post("is");
bb.Post("a");
bb.Post("test");
}
public class DataflowEx
{
public static TransformManyBlock<T, T> CreateDistinctBlock<T>()
{
var hs = new HashSet<T>();
//hs will be captured in the closure of the delegate
//supplied to the TransformManyBlock below and therefore
//will have the same lifespan as the returned block.
//Look up the term "c# closure" for more info
return new TransformManyBlock<T, T>(
x => Enumerable.Repeat(x, hs.Add(x) ? 1 : 0));
}
}
这样做的原因是,就像Linq的SelectMany一样,TransformManyBlock有效地展平了列表列表。因此,TransformManyBlock采用返回IEnumerable<T>
的委托,但一次提供返回的IEnumerable<T>
中的项目。通过返回其中包含0或1个项目的IEnumerable<T>
,我们可以有效地创建Where
- 类似行为,允许项目通过或阻止它通过,具体取决于某些谓词是否为满意。在这种情况下,谓词是否我们可以将项添加到捕获的HashSet中。