5

I'm looking for a design pattern that would fit my application design.

My application processes large amounts of data and produces some graphs. Data processing (fetching from files, CPU intensive calculations) and graph operations (drawing, updating) are done in seperate threads.

Graph can be scrolled - in this case new data portions need to be processed. Because there can be several series on a graph, multiple threads can be spawned (two threads per serie, one for dataset update and one for graph update).

I don't want to create multiple progress bars. Instead, I'd like to have single progress bar that inform about global progress. At the moment I can think of MVC and Observer/Observable, but it's a little bit blurry :) Maybe somebody could point me in a right direction, thanks.

4

4 回答 4

6

我曾经花了一周的大部分时间试图在一个非常复杂的算法上制作一个平滑、不卡顿的进度条。

该算法有 6 个不同的步骤。每个步骤都具有严重依赖于 A) 正在处理的基础数据的时序特征,不仅是数据的“数量”,还包括数据的“类型”和 B) 随着 CPU 数量的增加,步骤 2 的扩展性非常好, 2 个步骤在 2 个线程中运行,2 个步骤实际上是单线程的。

与核心数量相比,数据混合对每个步骤的执行时间的影响要大得多。

最终破解它的解决方案非常简单。我制作了 6 个函数来分析数据集并尝试预测每个分析步骤的实际运行时间。每个函数中的启发式都分析了正在分析的数据集和 CPU 的数量。根据我自己的 4 核机器的运行时数据,每个函数基本上都返回了我机器上预期需要的毫秒数。

f1(..) + f2(..) + f3(..) + f4(..) + f5(..) + f6(..) = 总运行时间,以毫秒为单位

现在有了这些信息,您可以有效地知道每个步骤应该占用的总执行时间的百分比。现在,如果您说 step1 应该占用 40% 的执行时间,那么您基本上需要找出如何从该算法中发出 40 个 1% 的事件。假设 for 循环正在处理 100,000 个项目,您可能会这样做:

for (int i = 0; i < numItems; i++){
     if (i % (numItems / percentageOfTotalForThisStep) == 0) emitProgressEvent();
     .. do the actual processing ..
}

这个算法给了我们一个丝般光滑的进度条,表现完美。您的实现技术可以在进度条中提供不同形式的缩放和功能,但考虑问题的基本方式是相同的。

是的,启发式参考编号是在我的机器上计算出来的,这并不重要——唯一真正的问题是,如果你想在另一台机器上运行时更改编号。但是您仍然知道比率(这是这里唯一真正重要的事情),因此您可以看到本地硬件的运行方式与我所拥有的不同。

现在普通的 SO 读者可能想知道为什么有人会花一周的时间制作一个平滑的进度条。该功能是销售主管要求的,我相信他在销售会议上使用它来获得合同。有钱能使鬼推磨 ;)

于 2009-02-14T21:09:28.943 回答
2

在这样的线程或异步进程/任务的情况下,我发现在主线程中有一个抽象类型或对象来表示(并且理想地封装)每个进程是很有帮助的。因此,对于每个工作线程,大概在主线程中都会有一个对象(我们称之为它Operation)来管理该工作线程,并且显然会有某种类似列表的数据结构来保存这些操作。

在适用的情况下,每个操作都为其工作人员提供启动/停止方法,并且在某些情况下 - 例如您的 - 表示该特定操作任务的进度和预期总时间或工作的数字属性。这些单位不一定需要基于时间,如果您知道您将执行 6,230 次计算,您可以将这些属性视为计算计数。此外,每个任务都需要有某种方式以任何适当的机制(回调、闭包、事件分派或您的编程语言/线程框架提供的任何机制)更新其当前进度的所属操作。

因此,当您的实际工作在单独的线程中执行时,“主”线程中的相应操作对象会不断更新/通知其工作人员的进度。进度条可以相应地更新自身,将操作的“预期”时间总和映射到其总时间,并将操作的“进度”总时间映射到其当前进度,以任何对您的进度条框架有意义的方式。

显然,在实际实现这一点时需要做很多其他的考虑/工作,但我希望这能给你它的要点。

于 2009-02-14T21:28:12.313 回答
1

Multiple progress bars aren't such a bad idea, mind you. Or maybe a complex progress bar that shows several threads running (like download manager programs sometimes have). As long as the UI is intuitive, your users will appreciate the extra data.

When I try to answer such design questions I first try to look at similar or analogous problems in other application, and how they're solved. So I would suggest you do some research by considering other applications that display complex progress (like the download manager example) and try to adapt an existing solution to your application.

Sorry I can't offer more specific design, this is just general advice. :)

于 2009-02-14T19:04:28.663 回答
1

Stick with Observer/Observable for this kind of thing. Some object observes the various series processing threads and reports status by updating the summary bar.

于 2009-02-14T19:09:25.250 回答