【问题标题】:What's the best way to calculate remaining download time?计算剩余下载时间的最佳方法是什么?
【发布时间】:2009-04-28 16:33:14
【问题描述】:

假设您要计算剩余下载时间,并且您拥有所有需要的信息,即:文件大小、dl'ed 大小、剩余大小、已用时间、瞬时 dl 速度等。 你将如何计算剩余的 dl 时间?

当然,直接的方法是:左尺寸/瞬时 dl 速度,或:(经过时间/dl'ed 尺寸)*左尺寸。 只是前者会受到瞬时速度的偏差,后者不能很好地适应变化的速度。

必须有一些更聪明的方法来做到这一点,对吧?查看您当前使用 uTorrent 下载的盗版软件和音乐。很容易注意到它比前面提到的简单计算做得更多。实际上,我注意到有时当 dl 速度下降时,剩余时间也会下降一段时间,直到它重新调整。

【问题讨论】:

    标签: download


    【解决方案1】:

    嗯,正如您所说,使用绝对当前的下载速度并不是一个好方法,因为它往往会波动。然而,像总体平均值这样的东西也不是一个好主意,因为那里也可能存在很大的波动。

    考虑一下我是否与其他 9 个人同时开始下载文件。我的速度只有正常速度的 10%,但文件进行到一半,其他 9 个完成。现在我的下载速度是开始时的 10 倍。我最初的 10% 速度不应该成为“还剩多少时间?”的一个因素。再计算。

    就个人而言,我可能会在过去 30 秒左右取平均值,然后使用它。那应该根据最近的速度进行计算,而不会剧烈波动。 30 秒可能不是正确的数量,需要一些实验才能确定合适的数量。

    另一种选择是设置一种“波动阈值”,在速度变化超过该阈值之前,您不会进行任何重新计算。例如(同样,随机数需要试验),您可以将阈值设置为 10%。然后,如果您以 100kb/s 的速度下载,则不会重新计算剩余时间,直到下载速度变为低于 90kb/s 或 110kb/s。如果发生其中一项更改,则会重新计算时间并设置新阈值。

    【讨论】:

    • 你和其他人提到的移动平均线似乎是朝着正确方向迈出的一步,而且我的直觉会比门槛法更好(当然,它们可以结合起来)。不过,我相信还有更好的方法。我猜速度直方图会包含大量信息,只是在这里想出低点。
    【解决方案2】:

    您可以使用旧值线性衰减的平均算法。如果 S_n 是时间 n 的速度,而 A_{n-1} 是时间 n-1 的平均值,则按如下方式定义您的平均速度。

    A_1 = S_1
    A_2 = (S_1 + S_2)/2
    A_n = S_n/(n-1) + A_{n-1}(1-1/(n-1))

    在英语中,这意味着过去进行的测量时间越长,它的重要性就越低,因为它的重要性已经减弱。

    将此与正常的平均算法进行比较: A_n = S_n/n + A_{n-1}(1-1/n)

    你也可以让它几何衰减,这将非常重视最近的速度: A_n = S_n/2 + A_{n-1}/2

    如果速度是 4,3,5,6 那么 A_4 = 4.5(简单平均)
    A_4 = 4.75(线性衰减)
    A_4 = 5.125(几何衰减)

    PHP 中的示例

    请注意,$n+1(不是$n)是当前数据点的数量,因为 PHP 的数组是零索引的。要匹配上面的示例,请设置n == $n+1n-1 == $n

    <?php
    
    $s = [4,3,5,6];
    
    // average
    $a = [];
    for ($n = 0; $n < count($s); ++$n)
    {
        if ($n == 0)
            $a[$n] = $s[$n];
        else
        {
            // $n+1 = number of data points so far
            $weight = 1/($n+1);
    
            $a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
        }
    }
    
    var_dump($a);
    
    
    // linear decay
    $a = [];
    for ($n = 0; $n < count($s); ++$n)
    {
        if ($n == 0)
            $a[$n] = $s[$n];
    
        elseif ($n == 1)
            $a[$n] = ($s[$n] + $s[$n-1]) / 2;
    
        else
        {
            // $n = number of data points so far - 1
            $weight = 1/($n);
    
            $a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
        }
    }
    
    var_dump($a);
    
    
    // geometric decay
    $a = [];
    for ($n = 0; $n < count($s); ++$n)
    {
        if ($n == 0)
            $a[$n] = $s[$n];
        else
        {
            $weight = 1/2;
    
            $a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
        }
    }
    
    var_dump($a);
    

    输出

    array (size=4)
      0 => int 4
      1 => float 3.5
      2 => float 4
      3 => float 4.5
    
    array (size=4)
      0 => int 4
      1 => float 3.5
      2 => float 4.25
      3 => float 4.8333333333333
    
    array (size=4)
      0 => int 4
      1 => float 3.5
      2 => float 4.25
      3 => float 5.125
    

    【讨论】:

    • 这很有趣。请记住,许多人在这里建议的移动平均线示例只是此方法的一个私人案例:在平均值上应用窗口函数。虽然“移动平均”示例中的函数只是一个脉冲函数,但它是一个更复杂的函数。假设速度偏差不遵循一定的逻辑,有趣的是哪种方法能产生更好的预测。
    • 这种方法的一个优点是您不需要保留值列表,而使用移动平均方法,您就可以做到。这种方法将产生比移动平均线更平滑的曲线,当异常值从平均值中删除时,移动平均线的反应会更加剧烈。
    • 我喜欢你的回答。您能否提供一些伪代码?
    • 我喜欢这个想法......似乎它会给出非常准确的结果!我很想在我的 Progression 库中实现它。
    • @DrewHoskins:感谢这个公式。我正在尝试实现这一点,并想检查我做得对。我用你的采样速度值 4、3、5、6 来检查你给出的结果和我计算的结果。对于几何衰减,我得到了相同的值,但对于 A_4,对于线性衰减,我得到 4.8333~。我的错误在哪里?线性衰减:A_1 = 4; A_2 = (4 + 3) / 2 = 3.5; A_3 = 5 / (3 - 1) + 3.5 * (1 - 1 / (3 - 1)) = 4.25; A_4 = 6 / (4 - 1) + 4.25 * (1 - 1 / (4 - 1)) = 4.8333 - 几何衰减:A_1 = 4; A_2 = (4 + 3) / 2 = 3.5; A_3 = 5 / 2 + 3.5 / 2 = 4.25; A_4 = 6 / 2 + 4.25 / 2 = 5.125
    【解决方案3】:

    显而易见的方法是介于两者之间,您需要下载速度的“移动平均线”。

    【讨论】:

      【解决方案4】:

      我认为这只是一个平均算法。它会在几秒钟内平均该速率。

      【讨论】:

        【解决方案5】:

        您还可以做的是跟踪您的平均速度并显示计算结果。

        【讨论】:

        • 如果我错了,请纠正我,但这与我提到的第二个选项相同。
        【解决方案6】:

        编辑:这是我最后的建议,我试过了,它提供了非常令人满意的结果:

        我有一个零初始化数组,每个下载速度在 0 - 500 kB/s 之间(如果您期望这样的速度可能会更高),步长为 1 kB/s。 我暂时对下载速度进行采样(每秒是一个很好的间隔),并将对应的数组项加一。 现在我知道以每种速度下载文件花了多少秒。所有这些值的总和就是经过的时间(以秒为单位)。这些值的总和乘以相应的速度就是到目前为止下载的大小。 如果我取数组中每个值与经过时间之间的比率,假设速度变化模式稳定,我可以形成一个公式来预测每个大小将花费的时间。在这种情况下,这个大小是剩余的大小。我就是做这个的: 我将每个数组项值的总和乘以相应的速度(索引)并除以经过的时间。然后我将剩下的大小除以这个值,就是剩下的时间。

        需要几秒钟才能稳定下来,然后效果非常好。

        请注意,这是一个“复杂”的平均值,因此丢弃旧值(移动平均值)的方法可能会进一步改进它。

        【讨论】:

        • 您可以添加统计分析,例如:“您的下载在 5 小时内完成了 95%”。
        • 更像是:“95% 的时间您以恒定速度下载,这会产生 5 小时的下载”。我认为任何用户都不会认同这样的预测。
        • 不不,我的意思是一个更复杂的解决方案,它基于对用户下载速度的统计分布的估计。您可以计算分布,然后确定最可能的结果。 (这可能会提供比平均更准确的解决方案,但平均已经相当不错了)。
        【解决方案7】:

        对于任何感兴趣的人,我用 C# 编写了一个名为 Progression 的开源库,它具有“移动平均”实现:ETACalculator.cs

        Progression 库定义了一个易于使用的结构,用于报告多种类型的进度。它还可以轻松处理嵌套进度,以实现非常流畅的进度报告。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多