进度条设计模式?

发布于 2024-08-26 12:06:14 字数 1161 浏览 6 评论 0原文

我正在编写的应用程序执行长度算法,通常需要几分钟才能完成。在此期间,我想向用户显示一个进度条,指示算法已尽可能精确地完成了多少。

该算法分为几个步骤,每个步骤都有自己的典型时序。例如 -

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

每个步骤都可以很容易地报告其进度通过设置其工作范围,例如 [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)
  ...
};

SubProgressMonitor 控制其父级的[parentFrom,parentFrom+parentLength] 范围。

通过这个方案,我能够根据全局计时中每个步骤的预期相对部分静态地划分顶级进度。然后,每个步骤可以进一步细分为多个部分等。

这样做的主要缺点是划分是静态的,并且根据运行时发现的变量进行更改会很痛苦。

那么问题是:是否有任何已知的进度监控设计模式可以解决这个问题?

The application I'm writing performs a length algorithm which usually takes a few minutes to finish. During this time I'd like to show the user a progress bar which indicates how much of the algorithm is done as precisely as possible.

The algorithm is divided into several steps, each with its own typical timing. For instance-

  • initialization (500 milli-sec)
  • reading inputs (5 sec)
  • step 1 (30 sec)
  • step 2 (3 minutes)
  • writing outputs (7 sec)
  • shutting down (10 milli-sec)

Each step can report its progress quite easily by setting the range its working on, say [0 to 150] and then reporting the value it completed in its main loop.

What I currently have set up is a scheme of nested progress monitors which form a sort of implicit tree of progress reporting.

All progress monitors inherit from an interface IProgressMonitor:

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

The root of the tree is the ProgressMonitor which is connected to the actual GUI interface:

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

Any other node in the tree are monitors which take control of a piece of the parent progress:

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

A SubProgressMonitor takes control of the range [parentFrom, parentFrom+parentLength] of its parent.

With this scheme I am able to statically divide the top level progress according to the expected relative portion of each step in the global timing. Each step can then be further subdivided into pieces etc'

The main disadvantage of this is that the division is static and it gets painful to make changes according to variables which are discovered at run time.

So the question: are there any known design patterns for progress monitoring which solve this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

墟烟 2024-09-02 12:06:14

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

Chris Harrison 发表了一篇关于用户如何根据报告的进度感知时间流逝的论文通过进度条(尽管所有实验中的实际持续时间显然是相同的)

请注意,首选显示公式是 (x + (1-x) / 2 )8 其中 x 是 0 到 1 范围内的实际进度 :)

因此,我建议:

  • 收集一些关于给定任务测量初始化的时间百分比的统计数据
  • ,并用它来衡量进度条上的进度,悲观(准备例如 10-15% 的缓冲区)
  • 就在最后一个任务(或最后几个任务,只要它们具有确定的持续时间)之前,全力以赴以便及时完成进度条(逐步加速)

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

A very interesting approach is the user perception.

Chris Harrison published a paper on how user perceives the time passing depending on the progress reported by the progress bar (although the actual duration was obviously identical in all experiments)

Note that the preferred display formula is (x + (1-x) / 2 )8 where x is the actual progress on a 0 to 1 scale :)

Therefore, I would suggest:

  • gather some statistics on the percentage of time a given task take
  • measure the initialization and use it to scale your progress on the progress bar, being pessimistic (prepare a buffer of 10-15% for example)
  • just before the last task (or few last tasks, as long as they have deterministic duration), go all out in order to complete the progress bar in time (with progressive speedup)

I know, that's not accurate, but if users think it's faster I'll settle for it!

水中月 2024-09-02 12:06:14

我在一个大型项目中采用了 Péter 的方法;在我们的试点和初始部署期间,我们数千台移动设备中的每一台都在发送回计时和使用数据,并且我们使用所用时间的平均值、中位数和标准差来微调任务的配置(当允许任务运行、允许运行多长时间、进度条显示中使用了哪些值等)。由于我们的解决方案的构建有点像您的解决方案,但由 XML 配置文件中提供的值驱动,因此我们考虑将其构建为自动化系统(例如,服务器会按一定时间间隔检查这些值,请注意某些任务最近花费了更长的时间)比以前多了几天,并更新配置文件以重新安排或延长时间),但我认为仅仅为了防止每隔几周进行一次快速的人工审查而麻烦是不值得的。

由于我不知道您的问题的技术解决方案,我认为您向用户展示的内容(以及您花费多少时间开发解决方案)应该基于功能问题:谁在使用这个?信息需要有多准确?这是一个交互过程,在此期间他们不能做其他工作,或者他们可以让它在后台运行并返回吗?您的长时间运行功能发生的工作流程是时间敏感型还是任务关键型流程?

很抱歉,我实际上无法为您提供您正在寻找的答案,但也许大体上思考一下您想要实现的目标会是一个好主意。 =)

Péter's was the approach I took on a large project; during our pilot and initial rollout, each of our thousands of mobile devices were sending back timing and usage data, and we used the average, median, and standard-deviations of the time taken to fine-tune the configuration of our tasks (when the task was allowed to run, how long it was allowed to run, what values were used in the progress-bar display, etc). Since our solution was built a bit like yours but driven by values supplied in an XML config file, we thought about building this as an automated system (e.g., the server would check these values on some interval, notice certain tasks were taking longer in recent days than they used to and update the config file to reschedule or lengthen them), but figured it wasn't worth the hassle just to prevent a quick human review every few weeks.

Since I don't know of a technical solution to your problem, I think what you show to the user (and how much time you spend developing a solution) should be based on functional concerns: who is using this? how accurate does the info need to be? Is this an interactive process during which they can do no other work, or can they let it run in the background and come back to it? Is the work process during which your long-running function occurs a time-sensitive or mission-critical one?

I'm sorry that I can't actually give you the answer you're looking for, but perhaps thinking about what you're trying to achieve in broad strokes knocks loose a good idea. = )

吾性傲以野 2024-09-02 12:06:14

构建一个 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 方法)以向用户显示进度。

Build an AggregateProgressMonitor that automatically calculates the child progress divisions based on information reported by the child progress monitors. The child progress monitor should at least inform the parent of "expected" running time. The child monitor estimated running times can then be updated by their respective operations based on runtime parameters and the overall progress reporting will be adjusted accordingly and automatically.

Something like this...

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);
  } 
};

You can even use the observed time of the first step to remap the subsequent progress reporters to be more accurate.

You'll need to keep an ordered map of some kind in the AggregateProgressMonitor to be able to track and calculate all the info from the children.

Once complete, you can extend AggregateProgressMonitor (overriding IProgressMonitor methods) to display the progress to the user.

北凤男飞 2024-09-02 12:06:14

这是一个棘手的问题,我们在之前的项目中也遇到过这个问题。

我能想到的最好办法是收集现实生活中每个阶段实际花费多长时间的统计数据,并相应地调整相对间隔长度。

不过,我们还没有在那个项目中实现它(至少在我在那里的时候),所以这只是一个理论想法:-)

This is a tough problem, we have struggled with it too in a previous project.

The best I could come up with is to collect statistics of how long each phase actually takes in real life, and adjust the relative interval lengths accordingly.

We haven't implemented it in that project though (at least as long as I was there), so this is just a theoretical idea :-)

巷雨优美回忆 2024-09-02 12:06:14

您可以考虑用进度圈替换进度条。如果任务有 N 个步骤,则在饼图中制作 N 个楔形,并在该步骤运行时像进度条一样填充每个楔形。

作为附加步骤,可能会为每个步骤显示一些文本,以便他们在步骤进行时可以阅读一些内容。

You might consider replacing the progress bar, with a progress circle. If the task has N steps, then make N wedges in the pie, and fill each wedge like a progress bar, as that step runs.

As an additional step, perhaps have some text displayed for each step, so they have something to read while the step progresses.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文