Функция PowerShell

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

Ответы на вопрос(15)

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

 Gabriel Espinoza18 окт. 2018 г., 13:40
спасибо за идею реализации простого решения, такого как метод расширения

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

 SsjCosty23 авг. 2016 г., 15:56
Спасибо, ваш ETACalculator работает очень хорошо!
 Gabriel Espinoza18 окт. 2018 г., 13:39
пожалуйста, создайте пакет NuGet
 Scott Rippey18 окт. 2018 г., 17:36
Извините, я на 7 лет устарел с опытом работы в .NET. Я был бы рад добавить в проект соавторов или даже передать право собственности, если вы хотите внести свой вклад в проект и помочь создать пакет NuGet :)
 Alexander28 сент. 2015 г., 13:57
Мне нравится часть "последние 10 секунд прогресса" ...
 Ahmed Abdelhameed22 мар. 2018 г., 06:29
Это на самом деле довольно хорошая библиотека. Я думаю, что если вы создадите для него пакет NuGet, он может стать популярным.

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

Функция PowerShell

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

    return [TimeSpan]::FromSeconds($secondsRemaining)
}

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

TimePerLine = Elapsed / LinesProcessed
TotalTime = TimePerLine * TotalLines
TimeRemaining = TotalTime - LinesRemaining * TimePerLine
 RayOldProf11 апр. 2013 г., 13:28
Немного править: TimeRemaining = (TotalTime - LinesRemaining) * TimePerLine
Решение Вопроса

(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 минут :-)

 Lucas10 февр. 2013 г., 22:36
Иногда, когда ваш мозг отключается, приятно найти кого-то, кто указал на очевидный ответ (только не такой очевидный после долгого дня взлома). Благодарю.
 17 of 2623 янв. 2009 г., 17:05
Может быть, я что-то здесь упускаю. Скажем, мы обработали 100 строк за 10 секунд, осталось 200 строк. Это дает нам (100/10) * 200 = 2000 секунд осталось. Теперь проходит 10 секунд без обработки строк. Теперь оставшееся время (100/20) * 200 = 1000 секунд осталось, даже если обработка не выполнялась.
 Pete Kirkham23 янв. 2009 г., 17:13
выражение должно быть (TimeTaken / linesProcessed) * linesLeft
 JoshBerke23 янв. 2009 г., 17:17
Да, выражение было неправильным ;-) Но это было правильно в духе вещей!
 Andrés08 окт. 2015 г., 16:02
Может быть, вы также должны иметь в виду, что в первом комментарии. Исправление сказанного: скажем, мы обработали 100 строк за 10 секунд, осталось 200 строк. Это дает нам (10/100) * 200 = 20 секунд до конца. Теперь проходит 10 секунд без обработки строк. Теперь оставшееся время составляет (20/100) * 200 = 40 секунд до конца, даже если обработка не выполнялась. С моей точки зрения, нужно пересчитывать время, оставшееся на каждой итерации, принимая во внимание не всю историю программы, а последние N времени / записей. KR

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

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

 Aaron Smith23 янв. 2009 г., 16:46
Вероятно, они не займут столько же времени, но я просто хочу оценить оставшееся время. Я знаю, что это не будет на 100% точно.

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

Время истекло и осталось время:
так что оставшееся время = всего необходимо - прошло

Моя идея / формула, скорее всего, так:

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

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

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

processingPerSecond и lastTickProcessed являются глобальными переменными вне метода таймера

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

но мы хотим показать случай 2. TimeLeft, так 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 в последнюю секунду

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

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

TimeElapsed * ((100% выполнено) /% выполнено) = оставшееся время

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

 Alireza Noori08 авг. 2013 г., 17:19
Так должно бытьTimeElapsed / Percent * 100.0

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

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

Я использовал это, чтобы пройти через набор записей (строки в файле 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")

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

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

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

 feedc0de25 авг. 2014 г., 23:55
Я получаю деление на ноль в itemsPerSecond = ... Мой процесс запускается 23:53:26, а мой DateTime.Now - 23:53:28. Почему деление на ноль?
 feedc0de26 авг. 2014 г., 14:31
Я использовал двойные числа вместо целых, и все работало!
 coloboxp26 авг. 2014 г., 14:07
Привет, Даниэль, TimeSpan (результат добавления или вычитания объектов DateTime), вероятно, имеет разницу в «ноль» секунд. В соответствии с вашими значениями это должно быть «2» секунды. Пожалуйста, проверьте значение «Ticks», чтобы убедиться, что оно отличается между «processStarted» и DateTime.Now.

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

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

индикаторы выполнения, которые плавно двигались к завершениюиндикаторы прогресса, которые ускорились к концу
 Aaron Smith03 нояб. 2009 г., 21:49
Я согласен Рассержен. Это намного лучше в Windows 7, как и все остальное в Windows 7.
 Aaron Smith23 янв. 2009 г., 16:56
Да, я прочитал этот пост. И я почувствовал влияние того, о чем он говорил. Копирование ощущалось ДЕЙСТВИТЕЛЬНО медленно в Vista, но, видимо, из-за индикатора выполнения, а не фактического времени, которое потребовалось.
 DisgruntledGoat06 авг. 2009 г., 13:49
Копированиеявляется очень медленно в Vista. И удаление, и удаление / обмен ...

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

timeLeft = timeSoFar * (1 / Процент)

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

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

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

B * C / A

 GWLlosa23 янв. 2009 г., 17:11
Вопрос о смене аппаратного обеспечения не имеет значения, так как вы работаете в режиме CURRENT для этого уравнения, и, вероятно, аппаратное обеспечение не слишком сильно меняется между строками 10 и 11.
 JoshBerke23 янв. 2009 г., 16:52
Какое время для обработки никогда не может быть полностью постоянным, не так ли? Разница может быть незначительной, особенно в небольших пакетах, но вы не можете управлять системой вне вашего собственного приложения, плюс она не будет постоянной между различными аппаратными средствами.

Ваш ответ на вопрос