当然,您可以将剩余的文件大小除以当前的下载速度,但如果您的下载速度波动(并且它会),则不会产生非常好的结果。什么是更好的算法来产生更平滑的倒计时?
答案 0 :(得分:113)
exponential moving average非常适合这一点。它提供了一种平滑平均值的方法,这样每次添加新样本时,较旧的样本对整体平均值变得越来越重要。它们仍然被考虑,但它们的重要性呈指数下降 - 因此得名。而且由于它是一个“移动”的平均值,你只需要保留一个数字。
在测量下载速度的上下文中,公式如下所示:
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 :(得分:7)
speed=speedNow*0.5+speedLastHalfMinute*0.3+speedLastMinute*0.2
答案 2 :(得分:7)
我多年前编写了一个算法来预测磁盘映像和多播程序中剩余的时间,该程序在当前吞吐量超出预定义范围时使用带有重置的移动平均值。它会保持顺畅,除非发生剧烈的事情,然后它会迅速调整,然后再次回到移动平均线。请参见此处的示例图表:
该示例图表中的粗蓝线是随时间变化的实际吞吐量。注意在传输的前半部分吞吐量低,然后在下半部分急剧上升。橙色线是整体平均值。请注意,它从未调整得足够远,无法准确预测完成所需的时间。灰线是移动平均线(即最后N个数据点的平均值 - 在该图中N为5,但实际上,N可能需要更大才能足够平滑)。它恢复得更快,但仍需要一段时间才能调整。较大的N需要更多的时间。因此,如果您的数据非常嘈杂,那么N必须更大,恢复时间也会更长。
绿线是我使用的算法。它就像移动平均线一样,但当数据超出预定范围(由浅蓝色和黄色线指定)时,它会重置移动平均线并立即跳起。预定义范围也可以基于标准偏差,因此可以根据数据的自动噪声进行调整。我只是将这些值扔到Excel中以便为这个答案绘制图表,因此它并不完美,但是你明白了。
可以设计数据以使该算法不能成为剩余时间的良好预测器。最重要的是,您需要大致了解数据的行为方式,并相应地选择算法。我的算法适用于我看到的数据集,因此我们继续使用它。
另一个重要提示是,开发人员通常会忽略进度条和时间估算计算中的设置和拆卸时间。这导致永久的99%或100%进度条长时间坐在那里(当缓存被冲洗或其他清理工作正在发生时)或者在扫描目录或其他设置工作时发生的早期估计,累积时间但不会产生任何百分比的进展,这会导致一切失败。您可以运行包含设置和拆卸时间的多个测试,并根据作业的大小估算这些时间的平均长度,并将该时间添加到进度条。例如,前5%的工作是设置工作,最后10%是拆解工作,然后中间的85%是下载或跟踪的任何重复过程。这也可以提供很多帮助。
答案 3 :(得分:5)
我认为您可以做的最好的事情是将剩余文件大小除以平均下载速度(到目前为止下载的速度除以您下载的时间长度)。这会稍微开始波动,但下载的时间会越来越稳定。
答案 4 :(得分:2)
在扩展到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波动。
答案 5 :(得分:1)
我发现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("--")
答案 6 :(得分:0)