Каков наилучший способ рассчитать оставшееся время загрузки?

Скажем, вы хотите рассчитать оставшееся время загрузки, и у вас есть вся необходимая информация, а именно: Размер файла, размер файла, размер слева, время истек, мгновенная скорость и т.д. ". Как бы вы вычислили оставшееся время dl?

Конечно, простой способ был бы либо: размер левой/мгновенной скорости dl, либо: (время, прошедшее /dl 'ed размер) * размер слева. Только то, что первое будет подвержено отклонениям в мгновенной скорости, и последнее не будет хорошо адаптироваться к изменению скоростей.

Должен быть какой-то более умный способ сделать это, правильно? Взгляните на пиратское программное обеспечение и музыку, которые вы загружаете с uTorrent. Легко заметить, что он делает больше, чем простой расчет, упомянутый ранее. На самом деле, я замечаю, что иногда, когда скорость dl падает, оставшееся время также падает на пару моментов, пока оно не изменится.

Ответ 1

Ну, как вы сказали, использование абсолютно текущей скорости загрузки не является отличным методом, потому что оно имеет тенденцию колебаться. Однако, что-то вроде общего среднего, тоже не очень хорошая идея, потому что там могут быть большие колебания.

Рассмотрим, если я начну загружать файл одновременно с 9 другими. Я получаю только 10% от моей обычной скорости, но на полпути через файл, остальные 9 заканчиваются. Теперь я загружаю в 10 раз скорость, с которой я начинал. Моя первоначальная 10-процентная скорость не должна быть фактором в "сколько времени осталось?" расчет больше.

Лично я, вероятно, возьму среднее за последние 30 секунд или около того, и использую это. Это должно делать расчеты, основанные на недавней скорости, без каких-либо колебаний. 30 секунд, возможно, не будет подходящей суммы, для получения хорошей суммы потребуется некоторое экспериментирование.

Другим вариантом было бы установить своего рода "порог флуктуации", в котором вы не будете выполнять пересчет до тех пор, пока скорость не изменится более чем на этот порог. Например (случайное число, опять же, потребует экспериментов), вы можете установить пороговое значение на уровне 10%. Затем, если вы загружаете со скоростью 100 кбит/с, вы не пересчитываете оставшееся время до тех пор, пока скорость загрузки не изменится ниже 90 кб/с или 110 кбит/с. Если происходит одно из этих изменений, время пересчитывается и устанавливается новый порог.

Ответ 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 (not $n) - это число текущих точек данных из-за того, что массивы PHP не обладали нулевым индексом. Чтобы соответствовать приведенному выше примеру, установите n == $n+1 или n-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

Ответ 3

Очевидным способом было бы нечто среднее между собой, вам нужно "скользящее среднее" скорости загрузки.

Ответ 4

Я думаю, что это просто алгоритм усреднения. Он усредняет скорость в течение нескольких секунд.

Ответ 5

То, что вы могли бы сделать, это отслеживать среднюю скорость и показывать результаты этого.

Ответ 6

EDIT: вот что я, наконец, предлагаю, я попробовал, и он дает вполне удовлетворительные результаты:

У меня есть нулевой инициализированный массив для каждой скорости загрузки от 0 до 500 кБ/с (может быть выше, если вы ожидаете такие скорости) с шагом 1 кБ/с. Я примеряю скорость загрузки мгновенно (каждая секунда - хороший интервал) и увеличивайте аргументированный элемент массива на единицу. Теперь я знаю, сколько секунд я потратил на загрузку файла с каждой скоростью. Сумма всех этих значений - это прошедшее время (в секундах). Сумма этих значений, умноженная на соответствующую скорость, - это размер, загруженный до сих пор. Если я принимаю соотношение между каждым значением в массиве и прошедшим временем, предполагая, что шаблон изменения скорости стабилизируется, я могу сформировать формулу для прогнозирования времени, которое потребуется каждому размеру. Этот размер в этом случае является оставшимся размером. Это то, что я делаю: Я беру сумму каждого значения элемента массива, умноженную на соответствующую скорость (индекс) и деленная на прошедшее время. Затем я делю размер, оставшийся на это значение, и оставшееся время.

Занимает несколько секунд, чтобы стабилизировать, а затем хорошо работает, черт побери.

Обратите внимание, что это "сложное" среднее значение, поэтому метод отбрасывания старых значений (скользящее среднее) может еще больше улучшить его.

Ответ 7

Для всех, кого это интересует, я написал библиотеку с открытым исходным кодом на С#, называемую Progression, которая имеет "скользящую среднюю" реализацию: ETACalculator.cs.

Библиотека Progression определяет простую в использовании структуру для сообщения о нескольких типах прогресса. Он также легко справляется с вложенным прогрессом для получения очень плавного отчета о ходе выполнения.