如何监控TPL Dataflow网格中的进度?

时间:2018-02-01 03:36:21

标签: c# task-parallel-library tpl-dataflow

我正在使用耗时的顺序工作流来处理C#应用程序,必须异步执行。它在用户按下按钮时开始,应用程序在几毫秒内收到从相机捕获的一些图像。然后工作流程。

  1. 将图像保存到磁盘
  2. 将它们对齐。
  3. 从中生成3d数据。
  4. 将它们分组为更大的集体对象(称为“扫描”)。
  5. 将可选分析数据添加到此扫描并执行。
  6. 最后保存扫描本身与图像一起保存到xml文件中。
  7. 其中一些步骤是可选的,可配置的。

    由于处理可能需要很长时间,因此通常会有一个等待处理的“扫描”队列所以我需要向用户呈现捕获的扫描队列的可视化表示,它们当前的处理状态(例如“保存”) ,“分析”,“完成”等。)

    我已经考虑过使用TPL DataFlow。但是虽然网格很容易创建,但我不知道如何监视正在发生的事情的状态,以便我可以更新用户界面。我是否尝试将回发消息的自定义操作块链接到UI?还有别的吗?

    TPL Dataflow是否适合这项工作?

1 个答案:

答案 0 :(得分:2)

报告总体进展

如果您认为TPL DataFlow图表有一个开始和结束块,并且您知道您在图表中发布了多少项目,那么您需要做的就是跟踪到达最终块的消息数量并将其与源进行比较发布到头部的消息数。这将允许您报告进度。

现在,如果块是1:1,这就可以轻松工作 - 也就是说,对于任何消息,只有一条消息输出。如果存在one:many阻止,则需要相应地更改进度报告。

报告工作阶段进度

如果您希望在整个图表中显示作业的进度,则需要将作业详细信息传递给每个块,而不仅仅是实际块所需的数据。作业是一项任务,必须跨越您问题中列出的所有步骤1-6。

因此,例如第2步可能需要图像数据才能执行对齐,但它并不关心文件名;工作中有多少步骤或其他与工作相关的步骤。没有足够的细节来了解当前作业的状态,或者难以仅根据块输入查找原始作业。你可以引用一些外部字典,但是图形在被隔离时最好设计,只处理传递到每个块的数据。

一个简单的例子就是改变这个最小代码:

var alignmentBlock = new TransformBlock<Image, Image>(n => { ... });

...为:

var alignmentBlock = new TransformBlock<Job, Job>(x => 
{
     job.Stage = Stages.Aligning;

     // perform alignment here
     job.Aligned = ImageAligner.Align (x.Image, ...);

     // report progress 

     job.Stage = Stages.AlignmentComplete;
});

...并重复其他块的过程。

舞台属性可以触发PropertyChanged通知或使用适合您的用户界面的任何其他形式的通知模式。

备注

现在您将注意到我引入了一个Job类,它作为每个块的唯一参数传递。 Job包含块的输入数据以及块输出的容器。

现在这会起作用,但是我的纯粹主义者认为最好将作业元数据分开,将TPL块输入和输出分开,否则会有来自多个线程的潜在状态损坏。

要解决此问题,您可能需要考虑使用Tuple<>并将其传递到块中。

e.g。

var alignmentBlock = new TransformBlock<Tuple<Job, UnalignedImages>, 
                                        Tuple<Job, AlignedImages>>(n => { ... });