C# 条件匹配时TPL数据流完成管道

C# 条件匹配时TPL数据流完成管道,c#,task-parallel-library,pipeline,tpl-dataflow,bufferblock,C#,Task Parallel Library,Pipeline,Tpl Dataflow,Bufferblock,我认为这是非常基本的方法,但我还没有找到任何例子。 我有一个生产者和一个消费者,我希望在至少处理x个对象时完成管道。此外,我需要知道收到了哪些对象 我就是这样做的: public class BlockTester { private static TransformBlock<int, int> _worker; public static async Task StartAsync() { _worker = new TransformB

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

我就是这样做的:

public class BlockTester
{
    private static TransformBlock<int, int> _worker;

    public static async Task StartAsync()
    {
        _worker = new TransformBlock<int, int>(s => s + s);
        var buffer = new BufferBlock<int>();
        var consumeTask = Consume(buffer);

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

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

        _worker.Complete();

        await buffer.Completion;

        if(buffer.TryReceiveAll(out var received))
        {
            Console.WriteLine(string.Join(", ", received));
        }
    }

    public static async Task<IReadOnlyCollection<int>> Consume(ISourceBlock<int> buffer)
    {
        var received = new List<int>();

        while (await buffer.OutputAvailableAsync())
        {
            var current = buffer.Receive();

            received.Add(current);

            if (current > 25)
            {
                _worker.Complete();
            }
        }

        return received;
    }
}
公共类BlockTester
{
私人静态转换块\u工人;
公共静态异步任务StartAsync()
{
_工人=新的转换块(s=>s+s);
var buffer=new BufferBlock();
var consumertask=consumer(缓冲区);
_LinkTo(缓冲区,新数据流链接选项{PropagateCompletion=true});
foreach(可枚举范围(0100)中的var值)
{
_工人岗位(价值);
}
_worker.Complete();
等待缓冲区。完成;
if(buffer.TryReceiveAll(接收到的输出变量))
{
Console.WriteLine(string.Join(“,”,received));
}
}
公共静态异步任务消耗(ISourceBlock缓冲区)
{
var received=新列表();
while(wait buffer.OutputAvailableAsync())
{
var current=buffer.Receive();
已收到。添加(当前);
如果(当前>25)
{
_worker.Complete();
}
}
收到的报税表;
}
}

我对缓冲区有点困惑。TryReceiveAll。等待consume任务和TryReceiveAll之间有什么区别?为什么TryReceiveAll在我的场景中是假的?我想我实现目标的方法还是有问题。

你的
消费方法应该是
动作块。无需使用
OutputAvailableAsync
TryRecieveAll
。用
ActionBlock
替换
BufferBlock
,并在
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.
    }
}
公共类BlockTester
{
//可以删除
私人静态转换块\u工人;
公共静态异步任务StartAsync()
{
//可以删除
_工人=新的转换块(s=>s+s);
var processor=newactionblock(x=>ProcessMessage(x));
_LinkTo(处理器,新数据流链接选项{PropagateCompletion=true});
foreach(可枚举范围(0100)中的var值)
{
_工人岗位(价值);
}
//_worker.Complete();
等待处理器完成;
}
私有静态int itemsRecieved=0;
公共静态void ProcessMessage(int x)
{
联锁增量(参考项目已确认);
如果(项目确认>25)u worker.Complete();
//处理消息
//记录消息等。
}
}
或使用复杂的消息对象:

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.
    }
}
公共类消息{}
公共类块测试器
{
//可以删除
私人静态转换块\u工人;
公共静态异步任务StartAsync()
{
//可以删除
_工人=新的转换块(s=>s);
var processor=newactionblock(x=>ProcessMessage(x));
_LinkTo(处理器,新数据流链接选项{PropagateCompletion=true});
foreach(Enumerable.Range(01100)中的var值)。选择(=>newmessage())
{
_工人岗位(价值);
}
//_worker.Complete();
等待处理器完成;
}
私有静态ConcurrentBag itemsRecieved=新ConcurrentBag();
公共静态无效处理消息(消息x)
{
已确认的项目。添加(x);
如果(itemsRecieved.Count>25)u worker.Complete();
//处理消息
//记录消息等。
}
}
编辑 回答原问题:

为什么
TryReceiveAll
返回false:


因为在运行
TryReceiveAll
时,
BufferBlock
已“完成”。对于要完成的块,其输出缓冲区中必须包含0项。
Consume
方法是在允许块完成之前将所有项目取出,最后在一个空块上调用
TryRecieveAll

您的
Consume
方法应该是
ActionBlock
。无需使用
OutputAvailableAsync
TryRecieveAll
。用
ActionBlock
替换
BufferBlock
,并在
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.
    }
}
公共类BlockTester
{
//可以删除
私人静态转换块\u工人;
公共静态异步任务StartAsync()
{
//可以删除
_工人=新的转换块(s=>s+s);
var processor=newactionblock(x=>ProcessMessage(x));
_LinkTo(处理器,新数据流链接选项{PropagateCompletion=true});
foreach(可枚举范围(0100)中的var值)
{
_工人岗位(价值);
}
//_worker.Complete();
等待处理器完成;
}
私有静态int itemsRecieved=0;
公共静态void ProcessMessage(int x)
{
联锁增量(参考项目已确认);
如果(项目确认>25)u worker.Complete();
//处理消息
//记录消息等。
}
}
或使用复杂的消息对象:

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.
    }
}
公共类消息{}
公共类块测试器
{
//可以删除
私人静态转换块\u工人;
公共静态异步任务StartAsync()
{
//可以删除
_工人=新的转换块(s=>s);
var processor=newactionblock(x=>ProcessMessage(x));
_LinkTo(处理器,新数据流链接选项{PropagateCompletion=true});
前面