2010-03-24 119 views
17

我正在写的应用程序执行一个长度算法,通常需要几分钟才能完成。在此期间,我想向用户展示一个进度条,该进度条表明算法的完成尽可能精确。进度条设计模式?

算法分为几个步骤,每个步骤都有其自己的典型时间。对于实例 -

  • 初始化(500毫秒)
  • 读取输入(5秒)
  • 步骤1(30秒)
  • 步骤2(3分钟)
  • 写入输出(7秒)
  • 关停(10毫秒)

每个步骤可通过设置第r相当容易地报告其进度比如说[0到150],然后报告它在主循环中完成的值。

我目前设置的是一个嵌套进度监视器的方案,它构成了一种隐式进度报告树。

所有进度监视从一个接口IProgressMonitor继承:

class IProgressMonitor 
{ 
public: 
    void setRange(int from, int to) = 0; 
    void setValue(int v) = 0; 
}; 

树的根是其连接到实际的GUI界面ProgressMonitor:

class GUIBarProgressMonitor : public IProgressMonitor 
{ 
    GUIBarProgressMonitor(ProgressBarWidget *); 
}; 

树中的任何其它节点是控制父项进程的一部分的监视器:

class SubProgressMonitor : public IProgressMonitor 
{ 
    SubProgressMonitor(IProgressMonitor *parent, int parentFrom, int parentLength) 
    ... 
}; 

A SubProgressMonitor取得其母公司的范围[parentFrom, parentFrom+parentLength]的控制权。

使用此方案,我可以根据全局时间中每个步骤的预期相对部分,静态划分顶级进度。然后每个步骤可以进一步细分为碎片等。'

这样做的主要缺点是划分是静态的,并且根据在运行时发现的变量进行修改变得非常痛苦。

所以问题:有没有已知的进度监测设计模式可以解决这个问题?

回答

1

这是一个棘手的问题,我们在之前的项目中也一直在努力。

我能想出的最好的结果是收集每个阶段在现实生活中实际需要多长时间的统计数据,并相应地调整相对间隔长度。

我们没有在该项目中实现它,虽然(至少只要我在那里),所以这只是一个理论概念:-)

4

彼得是我把一个大项目的做法;我们的导频和初始部署期间,我们的每个数千个移动设备中的被发回的定时和使用数据,并使用了平均,中值,以及所采取微调我们的任务配置的时间标准偏差(当允许任务运行,允许运行多长时间,在进度条显示中使用了什么值等)。由于我们的解决方案是建立一个有点像你的,但在一个XML配置文件中提供的值驱动,我们认为关于建立这个作为一个自动系统(例如,服务器会检查一些间隔这些值,发现某些任务是在最近的时间要长天,比他们曾经和更新配置文件重新安排或延长它们),但想通这是不值得只是为了防止每隔几周的迅速人工审核的麻烦。

因为我不知道的技术解决您的问题,我想你展示给用户(多少时间,你花开发解决方案),应根据功能性的关注什么:谁在使用呢?这些信息有多准确?这是一个互动的过程,在此期间,他们可以做任何其他工作,也可以让它在后台运行,回来了吗?工作过程中,您的长时间运行功能是对时间敏感还是关键任务?

对不起,我实际上没有给你你正在寻找的答案,但也许想想你想要在广泛的笔触中实现什么,会打消一个好主意。 =)

5

一个非常有趣的方法是用户感知。

Chris Harrison发表了关于用户根据由进度条报告的进展的时间的推移(虽然实际持续时间是在所有实验中明显相同)

注意的是,优选显示的公式是(如何感知纸张X + (1-X)/ 2)其中x是在0到1分的实际进度:)

因此,我建议:

  • 收集在时间的百分比一些统计数据给定的任务采取
  • 措施初始化,并用它来缩放进度条上你的进步,悲观
  • 前刚刚过去的(准备例如10-15%的缓冲区)任务(或者几个最后的任务,只要它们具有确定性的持续时间),全力以赴地完成进度条(以渐进式加速)

我知道,这并不准确,但如果用户认为它更快,我会解决它!

0

您可能会考虑用进度循环替换进度栏。如果任务有N个步骤,则在饼图中制作N个楔形,然后像步骤栏一样填充每个楔形。

作为一个额外的步骤,可能每个步骤都显示一些文本,所以在步骤进行时他们有一些东西需要阅读。

2

构建一个AggregateProgressMonitor,它可以根据子进度监视器报告的信息自动计算子进程的分区。儿童进展监测员至少应通知家长“预计”的运行时间。然后,可以根据运行参数通过各自的操作更新子监视器估计的运行时间,并且整体进度报告将相应地自动进行调整。

事情是这样的......

class IAggregateProgressMonitor : public IProgressMonitor 
{ 
    void setChildValue(IProgressMonitor *, int v); 
    void setChildEstimatedTime(IProgressMonitor *, int v); 
} 

class AggregateProgressMonitor : public IAggregateProgressMonitor 
{ 
    void setChildValue(IProgressMonitor * child, int v) 
    { 
     int aggregateValue = mapChildValueToAggregateValue(child, v); 
     setValue(aggregateValue); 
    } 

    void setChildEstimatedTime(IProgressMonitor * child, ulong ms) 
    { 
     children[child]->estimatedTime = ms; 
     updateChildProgressRatios(); 
    } 
} 

class SubProgressMonitor : public IProgressMonitor 
{ 
    SubProgressMonitor(IAggregateProgressMonitor *parent, int parentFrom, 
        int parentLength) ... ; 
    void setValue(int v) 
    { 
    parent->setChildValue(this, v); 
    } 

    void setEstimatedRunningTime(ulong ms) 
    { 
    parent->setChildEstimatedTime(this, ms); 
    } 
}; 

你甚至可以使用的第一步的观察时间重映射的后续进展记者更准确。

您需要在AggregateProgressMonitor中保留某种有序地图,以便能够跟踪和计算来自子项的所有信息。

完成后,您可以扩展AggregateProgressMonitor(覆盖IProgressMonitor方法)以向用户显示进度。