我正在使用C#应用程序,该应用程序具有必须异步执行的耗时的顺序工作流。它在用户按下按钮时启动,并且该应用在短短几毫秒内收到从相机捕获的一些图像。然后工作流程。


将图像保存到磁盘
对齐它们。
从它们生成3d数据。
将它们分组为更大的集合对象(称为“扫描”)。
将可选的分析数据添加到此扫描并执行它。
最终保存扫描本身,并与图像一起保存到xml文件中。


其中一些步骤是可选的和可配置的。

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

我已经研究过为此使用TPL DataFlow。但是,尽管网格很容易创建,但我并没有获得如何监视正在进行的状态以便更新用户界面的方式。我是否尝试链接自定义操作块,以将其回传到UI的消息?还有吗

TPL Dataflow甚至是这项工作的正确工具吗?

最佳答案

报告总体进展

当您考虑到TPL DataFlow图具有开始和结束块,并且知道向该图发布了多少个项目时,您要做的就是跟踪到达最后一个块的消息数量,并将其与消息的源计数进行比较。被张贴到头部。这将允许您报告进度。

现在,如果块为1:1,这很简单-也就是说,对于其中的任何消息,只有一条消息输出。如果存在一个“很多”块,则需要相应地更改进度报告。

报告作业阶段进度

如果您希望在整个图形中显示作业的进度,则需要将作业详细信息传递给每个块,而不仅是实际块所需的数据。一项工作是一项任务,必须跨越问题中列出的所有步骤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;
});


...并对其他模块重复该过程。

stage属性可以触发PropertyChanged通知,也可以使用适合您的UI的任何其他形式的通知模式。

笔记

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

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

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

例如

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

关于c# - 如何监视TPL Dataflow网格中的进度?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48554941/

10-13 04:37