我有一个指令循环,例如(伪代码):
for i = 1 to 1000000
// Process the ith input
doSomething(input[i])
end
这需要很长时间才能完成。我想向用户输出一些进度,更重要的是剩余时间估计,以便他们可以决定是否应该坐在那里玩弄拇指,去喝杯咖啡,去散步,或者去一个一周的假期到欧洲,而算法处理它的数字。
为了简化问题,您可以假设迭代次数会很大(例如,大于 100,因此您可以在每个百分位打印进度)。
一种常见的算法是简单地测量最后一次迭代所用的时间,然后将其乘以剩余的迭代次数并将其作为输出。如果每次迭代在执行所需的时间上可能有很大差异,这就会崩溃。
另一种方法是将自第一次迭代以来经过的时间除以完成的迭代次数,然后将其乘以剩余的迭代次数。如果迭代的持续时间不是均匀分布的,这就会崩溃。例如,如果前几个输入是“困难的”并且在接近输入数组的末尾变得更容易,则算法将高估剩余时间,直到它几乎完成(此时它会略微高估)。
那么,当每次迭代所花费的时间是迭代纵坐标的非直接的、任意的函数(这样简单地分析推导和实现每次迭代的完成时间是不切实际的)时,如何才能更好地估计剩余时间?
我可以想象的两个想法可能是富有成效的研究途径,但目前无法充分探索自己:
- 完成每个过去迭代的时间乘以剩余迭代的指数平均值。
- 用于完成每次迭代的跟踪时间,然后拟合函数并进行外推。
为什么计算密集型解决方案(如拟合方程)可以:
首先,对于值得讨论的真正大型任务,运行时间可能以小时或天为单位来衡量。现在复杂的数学运算需要几毫秒,所以增加的负担不会很大——在我上面的例子中,显然doSomething
需要很长时间才能使做一些数学的成本相形见绌,否则我不会太在意精确估计剩余时间第一名。
其次,例如,可以将迭代分箱成百分位数。然后,估计器不会对“完成的迭代与所用时间”的数据集进行操作,而是对最多具有 100 个数据点的“完成百分比与所用时间”的数据集进行操作。这提供了进一步的复杂性:假设您的任务需要一天或更长时间才能完成。仅估计剩余时间的每一个百分比是完整的,这意味着对估计函数进行 100 次评估。当你已经花了一天的时间,额外的一分半钟来估计剩余时间没什么大不了的,但这已经给了你一个 1 秒的窗口来拟合方程,还有什么不是 - 1 秒是做数学的很多时间在现代系统上。因此,我欢迎计算密集型解决方案。
tl;dr:如何为非常冗长的任务过度设计一个准确的剩余时间估计函数。