如何迭代BufferBlock中的项<t>?</t>

时间:2013-12-28 00:17:32

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

我最近开始使用.NET 4.5中的TPL Dataflow库,整个块的概念对我来说都是新的。我正在我的应用程序中实现生产者 - 消费者队列,我需要防止重复的消息被放入队列,因此需要检查消息是否已经排队。我使用的是BufferBlock<Message>类型(Message是自定义类型)。 BufferBlock具有Count属性,但在此问题中没有帮助,因为需要唯一标识消息。

有没有办法检查BufferBlock是否包含某个项目,或者检查所有项目并进行检查?是否可以将BufferBlock转换为允许迭代项目的内容?我正在关注example I saw on MSDN并且它不会检查项目是否在队列中,但我认为检查队列的内容是一项非常需要的操作。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:5)

为什么不将BufferBlock插入到为您执行此操作的链中,而不是闯入TransformManyBlock?您可以使用HashSetAdd方法仅在尚未添加项目的情况下返回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中。