如何在TPL中实现连续运行的数据流块?

时间:2013-12-02 19:00:58

标签: c# task-parallel-library .net-4.5 tpl-dataflow

我使用BufferBlock和ActionBlock设置了生产者/消费者数据流块,它在Console应用程序中运行良好;

将所有项目添加到BurfferBlock并将BufferBlock与其他Action Item链接后;它运作良好。

现在我想使用内部服务,此数据流块管道将始终处于启动状态,并且当消息通过外部事件可用时,它将进入缓冲区块并开始处理。我怎样才能做到这一点?

到目前为止,我已经完成了以下工作:

public void SetupPipeline()
{
    FirstBlock = new ActionBlock<WorkItem>(new Action<WorkItem>(ProcessIncomingMessage),
    new ExecutionDataflowBlockOptions
    {
        MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
    });

    BufferBlock = new BufferBlock<WorkItem>();

    GroupingDataflowBlockOptions GroupingDataflowBlockOptions = new GroupingDataflowBlockOptions();
    GroupingDataflowBlockOptions.Greedy = true;
    GroupingDataflowBlockOptions.BoundedCapacity = GroupingDataflowBlockOptions.Unbounded;
    CancellationTokenSource = new CancellationTokenSource();
    CancellationToken = CancellationTokenSource.Token;
    GroupingDataflowBlockOptions.CancellationToken = CancellationToken;
    BatchBlock = new BatchBlock<WorkItem>(BoundingCapacity, GroupingDataflowBlockOptions);

    ProcessItems = new ActionBlock<WorkItem[]>(WorkItems =>
        ProcessWorkItems(WorkItems.ToList<WorkItem>()),
        new ExecutionDataflowBlockOptions
      {
          CancellationToken = CancellationToken
      });

    Timer = new Timer(_ =>
            BatchBlock.TriggerBatch()
        );

    TimingBlock = new TransformBlock<WorkItem, WorkItem>(WorkItem =>
    {
        Timer.Change(TimerInterval, Timeout.Infinite);
        logger.Debug("Inside TimingBlock : " + WorkItem.ToString());
        return WorkItem;
    }, new ExecutionDataflowBlockOptions
    {
        CancellationToken = CancellationToken
    });

    BatchBlock.LinkTo(ProcessItems);
    TimingBlock.LinkTo(BatchBlock);
    BufferBlock.LinkTo(TimingBlock);
}

2 个答案:

答案 0 :(得分:2)

作为一个粗略的过度简化,DataFlow是一种使用一组方法处理大量对象的方法。它不提供或期望创建这些对象的任何特定方式。

如果您希望管道保持活动状态,请不要终止该应用程序。如果您不想使用控制台应用程序,请创建一个构建管道的服务,并将对象发送给它直到它关闭。

消息只是您将通过读取数据,响应事件(无论这意味着什么)或任何其他方式创建的对象。

至于外部事件,你是什么意思?有人会将数据发送到您的应用程序?有很多方法可以实现:

  • 如果数据来自另一个控制台应用程序,您可以将一个应用程序的结果传递给另一个应用程序,解析来自命令行应用程序输入流的数据,创建消息并将它们传递给管道
  • 如果您希望服务侦听请求,您可以托管.NET Pipe,WCF或Web API服务来侦听调用并将发布的数据传递给管道。
  • 如果数据来自数据库,您可以轮询更改并将任何已更改的数据发送到管道。

重点是,Dataflow是关于处理数据,而不是关于收听事件。它不是一个完整的分布式代理系统,如果你正在寻找它。

答案 1 :(得分:2)

您的批量大小由变量&#39; BoundingCapacity&#39;定义。在批处理块构造函数中。批次将在以下时间发布:

  • 已收到一些等于批量大小的帖子(在构造函数中指定)
  • 批次块标记为完成
  • 触发器方法称为

似乎您希望在满足浴槽尺寸或发生超时时发布批次。如果是这种情况,并且批量大小并不重要,我实际上只是向您拥有的计时器添加一个重复间隔,并使批处理块下游的对象忽略空帖。

您可能真正想要的,以及与数据流编程理念最相似的是,当您开始发布一系列项目然后在完成或超时发生时完成它时,创建一个新的批处理块。如果尚不存在,则新帖子将创建新的批处理块。

尝试围绕仅基于第一个触发器触发的批处理块实现超时计时器的问题是,您需要计算并验证缓冲区的帖子,或者您需要查看缓冲区块中的帖子。这两种情况都会造成很多丑陋和/或违反块封装。