[英]TPL Dataflow Complete Pipeline when condition matches
我認為這是一種非常基本的方法,但尚未找到任何示例。 我有一個生產者和一個消費者,我想在處理至少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;
}
}
我對buffer.TryReceiveAll有點困惑。 等待消耗任務和TryReceiveAll有什么區別? 為什么在我的情況下TryReceiveAll為假? 我想我達到目標的方法仍然存在問題。
您的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
已“完成”。 要完成一個塊,它的輸出緩沖區中必須包含0個項目。 Consume
方法是在允許該塊完成之前拉出所有項目,最后您將在一個空塊上調用TryRecieveAll
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.