如何准确估算下载剩余时间?

69

当然,你可以通过将剩余文件大小除以当前下载速度来计算下载所需时间,但如果你的下载速度波动较大(而且它会),这样计算出来的结果并不是很准确。那么有没有更好的算法来产生更平滑的倒计时呢?

6个回答

129

一种指数移动平均非常适合这种情况。它提供了一种将平均值平滑化的方法,因此每次添加新样本时,较旧的样本对整体平均值的重要性逐渐降低。 它们仍然被考虑在内,但其重要性呈指数级下降--因此得名。由于它是“移动”的平均值,您只需要保留一个数字。

在衡量下载速度的背景下,公式如下:

averageSpeed = SMOOTHING_FACTOR * lastSpeed + (1-SMOOTHING_FACTOR) * averageSpeed;

SMOOTHING_FACTOR 是一个介于 0 和 1 之间的数字。这个数字越高,旧样本被丢弃得越快。正如你在公式中看到的那样,当 SMOOTHING_FACTOR 为 1 时,你只是使用了你最后一次观察的值。当 SMOOTHING_FACTOR 为 0 时,averageSpeed 永远不会改变。所以,你需要介于两者之间的某些值,通常选择一个较低的值来获得良好的平滑效果。我发现 0.005 对于平均下载速度提供了相当不错的平滑效果。

lastSpeed 是最后一次测量的下载速度。你可以通过每秒运行一个计时器来获取这个值,以计算自上次运行以来下载了多少字节。

averageSpeed 显然是你要用来计算估计剩余时间的数值。将其初始化为你获取到的第一个 lastSpeed 值。


1
不清楚剩余下载时间。可以通过移动采样计算平均速度。 - byJeevan
也许值得一提的是:只有在时间采样率大致相同的情况下,EMA才能正常工作。例如,如果下载更新速率是每1 MB而不是每1秒,并且速度波动,则输出很可能是无意义的。 - wondra

18
多年前我编写了一个算法,用于预测磁盘映像和多播程序中剩余时间的移动平均,并在当前吞吐量超出预定义范围时进行重置。这个算法能够使数据平滑处理,除非发生了一些剧烈的情况,那么它会快速调整,然后再次返回到移动平均状态。请参见以下示例图表:enter image description here 在这个示例图表中,粗蓝线是随时间变化的实际吞吐量。请注意,在传输的前半段期间,吞吐量较低,然后在后半段急剧增加。橙色线是总体平均值。请注意,它从未调整得足够高,以便准确预测完成所需的时间。灰线是移动平均值(即最近N个数据点的平均值 - 在此图中N为5,但实际上,N可能需要更大才能足够平滑)。它恢复得更快,但仍需要一段时间来调整。N越大,需要的时间就越长。因此,如果您的数据相当嘈杂,则N就必须更大,恢复时间就会更长。 绿线是我使用的算法。它与移动平均线一样运行,但当数据移动到预定义范围之外时(由浅蓝色和黄色细线指定),它会重置移动平均值并立即跳上去。预定义范围也可以基于标准偏差进行调整,因此它可以自动适应数据的嘈杂程度。我只是将这些值放入Excel中以图表形式呈现,所以它并不完美,但您可以理解其中的意思。 然而,数据可能被虚构以使该算法无法成为一个好的剩余时间预测器。最重要的是,您需要对数据如何行为有一个大致的了解,并相应地选择算法。我的算法适用于我看到的数据集,因此我们一直在使用它。另一个重要的提示是,通常开发人员在进度条和时间估算计算中忽略安装和拆卸时间。这会导致永恒的99%或100%进度条长时间停留(当缓存被清除或其他清理工作正在进行时),或者在扫描目录或其他设置工作发生时出现过早的估计,累积时间但不累积任何百分比进度,从而混淆一切。您可以运行几个包含安装和拆卸时间的测试,并根据作业的大小平均估算这些时间,然后将该时间添加到进度条中。例如,前5%的工作是设置工作,最后10%的工作是拆卸工作,然后中间的85%是下载或其他重复过程,您可以跟踪这些过程。这也可以很大程度上帮助您。

1
好的技巧!谢谢你的分享。 - mpen

7
speed=speedNow*0.5+speedLastHalfMinute*0.3+speedLastMinute*0.2

1
加权,强调更近期的时间。 - mpen

6

我认为最好的做法是将剩余文件大小除以平均下载速度(已下载部分除以下载时间)。这个值一开始会有些波动,但随着下载时间的增加,会越来越稳定。


但是考虑到用户在过去24小时内一直在下载,几分钟前互联网连接刚刚中断,而用户看到的下载时间不是无限的情况呢?这是一个错误还是一个特性? - TiansHUo
如果连接保持中断,下载时间将趋近于无穷大。 - Andreas Brinck
1
是的...我不认为我喜欢这个解决方案。它过于强调下载速度,而且几个小时前就已经这样了。特别让我困扰的是,下载的前几秒钟通常非常不稳定,因为它正在加速(种子连接更多)或减速(Shaw的powerboost耗尽),因此我认为应该完全忽略它们。 - mpen
这是最简单的解决方案。实现移动平均可能更准确,但需要你以一致的方式跟踪速度并进行更新。 - Cerin

4

我发现Ben Dolman的回答非常有帮助,但对于像我这样不太擅长数学的人来说,仍然需要花费大约一个小时才能完全将其实现到我的代码中。以下是在Python中以更简单的方式表达相同内容的方法,如果有任何不准确之处,请让我知道,但在我的测试中它非常有效:

def exponential_moving_average(data, samples=0, smoothing=0.02):
    '''
    data: an array of all values.
    samples: how many previous data samples are avraged. Set to 0 to average all data points.
    smoothing: a value between 0-1, 1 being a linear average (no falloff).
    '''

    if len(data) == 1:
        return data[0]

    if samples == 0 or samples > len(data):
        samples = len(data)

    average = sum(data[-samples:]) / samples
    last_speed = data[-1]
    return (smoothing * last_speed) + ((1 - smoothing) * average)

input_data = [4.5, 8.21, 8.7, 5.8, 3.8, 2.7, 2.5, 7.1, 9.3, 2.1, 3.1, 9.7, 5.1, 6.1, 9.1, 5.0, 1.6, 6.7, 5.5, 3.2] # this would be a constant stream of download speeds as you go, pre-defined here for illustration

data = []
ema_data = []

for sample in input_data:
    data.append(sample)
    average_value = exponential_moving_average(data)
    ema_data.append(average_value)

# print it out for visualization
for i in range(len(data)):
    print("REAL: ", data[i])
    print("EMA:  ", ema_data[i])
    print("--")

3

除了Ben Dolman的答案外,您也可以在算法中计算波动。这将使其更加平滑,但也会预测平均速度。

类似这样:

prediction = 50;
depencySpeed = 200;
stableFactor = .5;
smoothFactor = median(0, abs(lastSpeed - averageSpeed), depencySpeed);
smoothFactor /= (depencySpeed - prediction * (smoothFactor / depencySpeed));
smoothFactor = smoothFactor * (1 - stableFactor) + stableFactor;
averageSpeed = smoothFactor * lastSpeed + (1 - smoothFactor) * averageSpeed;

无论是否波动,只要设置正确,使用预测值和依赖速度,它将与其他设置一样稳定。根据你的互联网速度稍微进行调整。这些设置非常适合平均速度为600 kB/s的情况,尽管会在0到1MB之间波动。


1
也许你可以基于以前的下载量来进行预测?随着时间的推移,它会变得更加准确。 - mpen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接