Рассчитать оставшееся время - PullRequest
53 голосов
/ 23 января 2009

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

Ответы [ 15 ]

56 голосов
/ 23 января 2009

Почему бы и нет?

(linesProcessed / TimeTaken) (timetaken / linesProcessed) * LinesLeft = TimeLeft

TimeLeft будет затем выражаться в любую единицу времени timeTaken.

Edit:

Спасибо за комментарий, вы правы, это должно быть:

(TimeTaken / linesProcessed) * linesLeft = timeLeft

так что у нас

(10 / 100) * 200 = 20 секунд Теперь проходит 10 секунд
(20 / 100) * 200 = 40 секунд осталось теперь еще 10 секунд, и мы обрабатываем еще 100 строк
(30 / 200) * 100 = 15 секунд, и теперь мы все видим, почему диалог копирования файла переходит с 3 часов до 30 минут :-)

28 голосов
/ 16 марта 2011

Я удивлен, что никто не ответил на этот вопрос с кодом!

Простой способ подсчета времени, на который отвечает @JoshBerke, можно кодировать следующим образом:

DateTime startTime = DateTime.Now;
for (int index = 0, count = lines.Count; index < count; index++) {
    // Do the processing
    ...

    // Calculate the time remaining:
    TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (count - (index+1)) / (index+1));

    // Display the progress to the user
    ...
}

Этот простой пример отлично подходит для простого расчета прогресса.
Однако для более сложной задачи есть много способов улучшить этот расчет!

Например, когда вы загружаете большой файл, скорость загрузки может легко колебаться. Чтобы рассчитать наиболее точное значение «ETA», хорошим алгоритмом будет учесть только последние 10 секунд прогресса. Проверьте ETACalculator.cs для реализации этого алгоритма!

ETACalculator.cs из Progression - библиотека с открытым исходным кодом, которую я написал. Он определяет очень простую в использовании структуру для всех видов «расчета прогресса». Это позволяет легко иметь вложенные шаги, которые сообщают о различных типах прогресса. Если вы беспокоитесь о воспринимаемой производительности (как предложено @JoshBerke), это вам очень поможет.

17 голосов
/ 23 января 2009

Обязательно управляйте воспринимаемой производительностью .

Хотя все индикаторы выполнения в тесте занимали одинаковое количество времени, две характеристики заставили пользователей думать, что процесс быстрее, даже если это не так:

  1. индикаторы прогресса, которые плавно двигались к завершению
  2. индикаторы прогресса, которые ускорились к концу
11 голосов
/ 26 июля 2011

Не для того, чтобы оживить мертвый вопрос, но я продолжал возвращаться, чтобы ссылаться на эту страницу.
Вы можете создать метод расширения для класса Stopwatch, чтобы получить функциональность, которая получит приблизительный оставшийся промежуток времени.

static class StopWatchUtils
{
    /// <summary>
    /// Gets estimated time on compleation. 
    /// </summary>
    /// <param name="sw"></param>
    /// <param name="counter"></param>
    /// <param name="counterGoal"></param>
    /// <returns></returns>
    public static TimeSpan GetEta(this Stopwatch sw, int counter, int counterGoal)
    {
        /* this is based off of:
         * (TimeTaken / linesProcessed) * linesLeft=timeLeft
         * so we have
         * (10/100) * 200 = 20 Seconds now 10 seconds go past
         * (20/100) * 200 = 40 Seconds left now 10 more seconds and we process 100 more lines
         * (30/200) * 100 = 15 Seconds and now we all see why the copy file dialog jumps from 3 hours to 30 minutes :-)
         * 
         * pulled from /343753/rasschitat-ostavsheesya-vremya#343761
         */
        if (counter == 0) return TimeSpan.Zero;
        float elapsedMin = ((float)sw.ElapsedMilliseconds / 1000) / 60;
        float minLeft = (elapsedMin / counter) * (counterGoal - counter); //see comment a
        TimeSpan ret = TimeSpan.FromMinutes(minLeft);
        return ret;
    }
}

Пример:

int y = 500;
Stopwatch sw = new Stopwatch();
sw.Start();
for(int x = 0 ; x < y ; x++ )
{
    //do something
    Console.WriteLine("{0} time remaining",sw.GetEta(x,y).ToString());
}

Надеюсь, это кому-нибудь пригодится.


РЕДАКТИРОВАТЬ: Следует отметить, что это наиболее точно, когда каждый цикл занимает одинаковое количество времени.
Изменить 2: Вместо создания подклассов я создал метод расширения.

3 голосов
/ 25 октября 2013

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

    /// <summary>
    /// Calculates the eta.
    /// </summary>
    /// <param name="processStarted">When the process started</param>
    /// <param name="totalElements">How many items are being processed</param>
    /// <param name="processedElements">How many items are done</param>
    /// <returns>A string representing the time left</returns>
    private string CalculateEta(DateTime processStarted, int totalElements, int processedElements)
    {
        int itemsPerSecond = processedElements / (int)(processStarted - DateTime.Now).TotalSeconds;
        int secondsRemaining = (totalElements - processedElements) / itemsPerSecond;

        return new TimeSpan(0, 0, secondsRemaining).ToString();
    }

Вам потребуется инициализировать переменную DateTime при запуске обработки и отправлять ее методу на каждой итерации.

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

Если вы используете потоки, вы можете попытаться установить текст с помощью метода Invoke(Action), было бы проще использовать этот метод расширения для простого архивирования .

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

Надеюсь, это кому-нибудь поможет.

3 голосов
/ 23 января 2009

Обычно при обработке вы знаете три вещи в любой момент времени:

  1. Сколько единиц / кусков / предметов было обработано до этого момента времени (A).
  2. Сколько времени понадобилось для обработки этих предметов (B).
  3. Количество оставшихся предметов (C).

С учетом этих предметов оценка (если время обработки элемента не является постоянным) оставшегося времени будет

B * C / A

2 голосов
/ 23 января 2009

Это сильно зависит от того, что такое «что-то». Если вы можете предположить, что время обработки каждой строки одинаково, вы можете сделать простой расчет:

TimePerLine = Elapsed / LinesProcessed
TotalTime = TimePerLine * TotalLines
TimeRemaining = TotalTime - LinesRemaining * TimePerLine
1 голос
/ 20 августа 2010

Где time$("ms") представляет текущее время в миллисекундах с 00: 00: 00.00, а lof представляет общее количество строк для обработки, а x представляет текущую строку:

if Ln>0 then
    Tn=Tn+time$("ms")-Ln   'grand total of all laps
    Rn=Tn*(lof-x)/x^2      'estimated time remaining in seconds
end if
Ln=time$("ms")             'start lap time (current time)
1 голос
/ 23 января 2009

нет стандартного алгоритма, о котором я знаю, мое предложение было бы:

  • Создать переменную для сохранения%
  • Рассчитайте сложность задачи, которую вы хотите отслеживать (или ее оценку)
  • Время от времени ставьте приращения в% так, как вы считаете нужным, учитывая сложность.

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

0 голосов
/ 12 августа 2018

Функция PowerShell

function CalculateEta([datetime]$processStarted, [long]$totalElements, [long]$processedElements) {
    $itemsPerSecond = $processedElements / [DateTime]::Now.Subtract($processStarted).TotalSeconds
    $secondsRemaining = ($totalElements - $processedElements) / $itemsPerSecond

    return [TimeSpan]::FromSeconds($secondsRemaining)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...