Подтвердить что ты не робот

Рассчитать оставшееся время

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

4b9b3361

Ответ 1

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

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

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

Изменить:

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

(timetaken / linesProcessed) * LinesLeft = TimeLeft

поэтому имеем

(10 / 100) * 200= 20 секунд спустя 10 секунд

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

Ответ 2

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

Простой способ рассчитать время, как ответил @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 - библиотека с открытым исходным кодом, которую я написал. Он определяет очень простую в использовании структуру для всех видов "расчета прогресса". Это позволяет легко вставлять шаги, сообщающие о разных типах прогресса. Если вы беспокоитесь о Perceived Performance (как предлагал @JoshBerke), это очень поможет вам.

Ответ 3

Убедитесь, что воспринимается производительность.

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

  • индикаторы прогресса, которые плавно продвигались к завершению
  • индикаторы прогресса, которые ускоряются до конца.

Ответ 4

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

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 http://stackoverflow.com/questions/473355/calculate-time-remaining/473369#473369
         */
        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: Вместо подкласса я создал метод расширения.

Ответ 5

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

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

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

B * C/A

Ответ 6

Я сделал это, и он работает неплохо, не стесняйтесь изменять подпись метода в соответствии с вашими типами переменных или также с типом возвращаемого значения, возможно, вы хотели бы получить объект 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), проще будет использовать этот метод расширения для архивирования.

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

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

Ответ 7

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

TimePerLine = Elapsed / LinesProcessed
TotalTime = TimePerLine * TotalLines
TimeRemaining = TotalTime - LinesRemaining * TimePerLine

Ответ 8

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

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

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

Ответ 9

Где 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)

Ответ 10

Это действительно зависит от того, что делается... строк недостаточно, если каждая отдельная строка не занимает столько же времени.

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

Ответ 11

Если вы знаете, что процент завершен, и вы можете просто предположить, что временные шкалы линейно, что-то вроде

timeLeft = timeSoFar * (1/Percentage)

может работать.

Ответ 12

Я уже знал, что процент завершен и время прошло, поэтому это помогло мне:

TimeElapsed * ((100%%)/% завершено) = TimeRemaining

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

Ответ 13

Существует 2 способа отображения времени

  • Время и время Осталось в целом: так что истекшее будет увеличиваться, но остальное будет, вероятно, стабильным общим временем (если в секунду стабильно)

  • Истекшее время и оставшееся время:
    поэтому Time Left = Total Needed - Elapsed

Моя идея/формула более вероятна:

Обработано - обновлено из текущего потока от 0 до Total

У меня есть таймер с интервалом 1000 мс, который вычисляет обрабатываемые в секунду:

processedPerSecond = Processed - lastTickProcessed;
lastTickProcessed = Processed;  //store state from past call

обработаноPerSecond и lastTickProcessed - глобальные переменные из метода таймера

Теперь, если мы хотим получить сколько секунд потребуется для завершения обработки (в идеальном постоянном предположении) totalSecondsNeeded = TotalLines/PerSecond

но мы хотим показать случай 2. TimeLeft so TimeLeftSeconds = (TotalLines - обработан)/PerSecond

TimeSpan remaining = new TimeSpan(0, 0, (transactions.Count - Processed) / processedPerSecond);
labelTimeRemaining.Text = remaining.ToString(@"hh\:mm\:ss");

Конечно, TimeLeftSeconds будет "прыгать", если PerSecond перескакивает, поэтому, если прошлое PerSecond было 10, а затем 30, а затем назад до 10, пользователь увидит его.

Существует способ вычисления среднего значения, но это может не показывать в реальном времени, если процесс ускоряется в конце

int perSecond = (int)Math.Ceiling((processed / (decimal)timeElapsed.TotalSeconds));  //average not in past second

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

Мы могли также вычислить и сохранить каждый PerSecond, затем взять последние 10 секунд и сделать среднее, но в этом случае пользователю придется ждать 10 секунд, чтобы увидеть первый расчет или мы можем показать время, начинающееся с первого раза в секунду, а затем постепенное среднее суммирование до 10 последних PerSecond

Надеюсь, мои "нервные" мысли помогут кому-то построить что-то удовлетворяющее.

Ответ 14

Как насчет этого....

Я использовал это, чтобы пройти через набор записей (строки в файле Excel в одном случае)

L - номер текущей строки X - общее количество строк dat_Start имеет значение Now(), когда начинается процедура

Debug.Print Format((L / X), "percent") & vbTab & "Time to go:" & vbTab & Format((DateDiff("n", dat_Start, Now) / L) * (X - L), "00") & ":" & Format(((DateDiff("s", dat_Start, Now) / L) * (X - L)) Mod 60, "00")