我认为这是非常基本的方法,但我还没有找到任何例子。 我有一个生产者和一个消费者,我想在处理至少x个对象时完成管道。另外,我需要知道收到了什么对象。
我就是这样做的:
as
我对buffer.TryReceiveAll有点困惑。等待消费任务和TryReceiveAll有什么区别?为什么TryReceiveAll在我的场景中是假的?我想我实现目标的方法仍然存在问题。
答案 0 :(得分:2)
您的Consume
方法应为ActionBlock
。无需使用OutputAvailableAsync
或TryRecieveAll
。将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
。