TPL DataFlow仅在处理完所有数据后才传播完成

时间:2018-07-26 14:35:36

标签: c# tpl-dataflow

我有一个生产者将数据发送到BufferBlock,并且从源中读取了所有数据后,它将调用Complete()

默认行为是,当调用完成时,即使缓冲区中仍然有消息,它也会沿管道传播完成。

是否需要等待告诉一个块:仅在缓冲区为空时才传播完成?

完成时,我在Receive上遇到了异常:InvalidOperationException: 'The source completed without providing data to receive.'

我当前正在使用:

var bufferBlock = new BufferBlock<string>();

var transformBlock = new TransformBlock<string, string>(s =>
{
    Thread.Sleep(50);

    return s;
});

bufferBlock.LinkTo(transformBlock, new DataflowLinkOptions { PropagateCompletion = true });

foreach (var i in Enumerable.Range(0, 10))
    bufferBlock.Post(i.ToString());

bufferBlock.Complete();

while (!transformBlock.Completion.IsCompleted)
    Console.WriteLine(transformBlock.Receive());

为避免这种情况,我目前正在使用:

while (bufferBlock.Count > 0)
    await Task.Delay(100);

bufferBlock.Complete();

听起来不是一个很干净的解决方案。

这是比赛条件吗?即阻止标记为未完成,并且在我打电话时它们已完成接收?

我想我可以将!transformBlock.Completion.IsCompleted替换为block.OutputAvailableAsync,对吗?

2 个答案:

答案 0 :(得分:0)

要等待管道完成,您应该等待管道中最后一个块的完成任务。在这种情况下,您应该将代码更改为:

foreach (var i in Enumerable.Range(0, 10))
    bufferBlock.Post(i.ToString());

bufferBlock.Complete();

await transformBlock.Completion;

这在Completing a pipelineWaiting for the pipeline to finishWalkthrough: Creating a Dataflow Pipeline段落中得到证明

TransformBlock已经有一个缓冲区,这意味着发布到输入BufferBlock的所有内容都将立即发送到TransformBlock。最好将其他块用于测试目的。本演练演示了一个很好的示例:一个transformBlock用于下载页面内容,另一个用于解析页面内容,等等。

请小心各种不幸的编码实践,例如每次创建一个新的HttpClient实例。下载器可以更改为:

  var httpClient=new HttpClient();
  var downloadString = new TransformBlock<string, string>(async uri =>
  {
     Console.WriteLine("Downloading '{0}'...", uri);

     return await httpClient.GetStringAsync(uri);
  });

答案 1 :(得分:0)

是的,手动从块中检索消息的正确方法是结合使用OutputAvailableAsyncTryReceive

while (await transformBlock.OutputAvailableAsync())
{
    while (transformBlock.TryReceive(out var item))
    {
        Console.WriteLine(item);
    }
}
await transformBlock.Completion; // Required to propagate exceptions

属性BufferBlock.CountTransformBlock.OutputCount等仅适用于监视和统计。在大多数情况下,使用它们来控制数据流是可能出现争用状况和潜在错误的指示。