条件匹配时的TPL数据流完整管道

时间:2018-03-08 21:05:39

标签: c# task-parallel-library pipeline tpl-dataflow bufferblock

我认为这是非常基本的方法,但我还没有找到任何例子。 我有一个生产者和一个消费者,我想在处理至少x个对象时完成管道。另外,我需要知道收到了什么对象。

我就是这样做的:

as

我对buffer.TryReceiveAll有点困惑。等待消费任务和TryReceiveAll有什么区别?为什么TryReceiveAll在我的场景中是假的?我想我实现目标的方法仍然存在问题。

1 个答案:

答案 0 :(得分:2)

您的Consume方法应为ActionBlock。无需使用OutputAvailableAsyncTryRecieveAll。将BufferBlock替换为ActionBlock,然后在ActionBlock内进行处理。除非你在这个过程中有多个步骤,否则你不清楚为什么你需要TransformBlock

public class BlockTester
{
    //Could be removed
    private static TransformBlock<int, int> _worker;

    public static async Task StartAsync()
    {
        //Could be removed
        _worker = new TransformBlock<int, int>(s => s + s);
        var processor = new ActionBlock<int>(x => ProcessMessage(x));

        _worker.LinkTo(processor, new DataflowLinkOptions { PropagateCompletion = true });

        foreach (var value in Enumerable.Range(0, 100))
        {
            _worker.Post(value);
        }

        //_worker.Complete();

        await processor.Completion;
    }


    private static int itemsRecieved = 0;
    public static void ProcessMessage(int x)
    {
        Interlocked.Increment(ref itemsRecieved);
        if (itemsRecieved > 25) _worker.Complete();
        //process the message
        //log the message etc.
    }
}

或者使用复杂的消息对象:

public class Message { }

public class BlockTester
{
    //Could be removed
    private static TransformBlock<Message, Message> _worker;

    public static async Task StartAsync()
    {
        //Could be removed
        _worker = new TransformBlock<Message, Message>(s => s);
        var processor = new ActionBlock<Message>(x => ProcessMessage(x));

        _worker.LinkTo(processor, new DataflowLinkOptions { PropagateCompletion = true });

        foreach (var value in Enumerable.Range(0, 100).Select(_ => new Message()))
        {
            _worker.Post(value);
        }

        //_worker.Complete();

        await processor.Completion;
    }


    private static ConcurrentBag<Message> itemsRecieved = new ConcurrentBag<Message>();
    public static void ProcessMessage(Message x)
    {
        itemsRecieved.Add(x);
        if (itemsRecieved.Count > 25) _worker.Complete();
        //process the message
        //log the message etc.
    }
}

修改 回答原来的问题:

  

为什么TryReceiveAll返回false:

因为在TryReceiveAll运行时,BufferBlock已完成&#34;已完成&#34;。对于要完成的块,它的输出缓冲区中必须包含0个项。在允许块完成之前,Consume方法将所有项目拉出来,并且您最终在空块上调用TryRecieveAll