testdome test online net knowledge examen espaƱol dome answers c# algorithm

c# - test - Calcule el tiempo restante



test online c# (14)

¿Qué es un buen algoritmo para determinar el tiempo restante para que algo se complete? Sé cuántas líneas totales hay, y cuántas ya se han completado, ¿cómo debo calcular el tiempo restante?


Depende mucho de lo que sea el "algo". Si puede asumir que la cantidad de tiempo para procesar cada línea es similar, puede hacer un cálculo simple:

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


En general, usted sabe tres cosas en cualquier momento mientras procesa:

  1. Cuántas unidades / trozos / elementos se han procesado hasta ese momento (A).
  2. Cuánto tiempo ha tardado en procesar esos elementos (B).
  3. El número de elementos restantes (C).

Dados esos ítems, la estimación (a menos que el tiempo para procesar un ítem sea constante) del tiempo restante será

B * C / A


Eso realmente depende de lo que se está haciendo ... las líneas no son suficientes a menos que cada línea tome la misma cantidad de tiempo.

La mejor manera (si sus líneas no son similares) probablemente sería mirar las secciones lógicas del código. Averigüe cuánto tiempo tarda cada sección en promedio, luego use esos tiempos promedio para estimar el progreso.


Si conoce el porcentaje completado, y simplemente puede suponer que el tiempo escalas linealmente, algo así como

timeLeft = timeSoFar * (1 / Porcentaje)

Podría funcionar.


no hay ningún algoritmo estándar que conozca, mi sugestión sería:

  • Crea una variable para guardar el%
  • Calcule la complejidad de la tarea que desea rastrear (o una estimación de la misma)
  • Ponga incrementos al% de vez en cuando como lo considere apropiado dada la complejidad.

Probablemente haya visto programas donde la barra de carga se ejecuta mucho más rápido en un punto que en otro. Bueno, eso es más o menos porque así es como lo hacen. (aunque probablemente solo pongan incrementos a intervalos regulares en el contenedor principal)


Donde el time$("ms") representa el tiempo actual en milisegundos desde 00: 00: 00.00, y lof representa el total de líneas a procesar, y x representa la línea actual:

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)


Ya sabía el porcentaje completo y el tiempo transcurrido, así que esto me ayudó:

TimeElapsed * ((100% completado) /% completado) = Tiempo restante

Luego actualicé este valor cada vez que% completo cambió, lo que me dio una ETA variable constante.


Hay 2 formas de mostrar el tiempo

  1. Tiempo transcurrido y Tiempo restante en general: así transcurre aumentará, pero el tiempo restante será probablemente el tiempo total necesario (si por segundo es estable)

  2. Tiempo transcurrido y tiempo restante:
    Tiempo restante = Total necesario: transcurrido

Mi idea / fórmula es más probable así:

Procesado: actualizado desde el hilo en ejecución desde 0 hasta Total

Tengo un temporizador con un intervalo de 1000 ms que calcula procesado por segundo:

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

processedPerSecond y lastTickProcessed son variables globales fuera del método de temporizador

Ahora, si quisiéramos obtener cuántos segundos se requieren para completar el procesamiento (en una suposición constante ideal) totalSegundos necesarios = Líneas totales / Por segundo

pero queremos mostrar el caso 2. TimeLeft entonces TimeLeftSeconds = (TotalLines - Processed) / PerSecond

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

Por supuesto, TimeLeftSeconds "saltará" si PerSecond salta, por lo que si pasa PerSecond fue 10 entonces 30 y luego vuelve a 10, el usuario lo verá.

Hay una forma de calcular el promedio, pero puede que no se muestre en tiempo real si el proceso se acelera al final

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

Por lo tanto, puede ser la elección de un desarrollador "elegir" un método que será más preciso en función de la predicción de cuán "agitado" es el procesamiento

También podríamos calcular y guardar cada PerSegundo, luego tomar los últimos 10 segundos y hacer un promedio, pero en este caso el usuario tendrá que esperar 10 segundos para ver el primer cálculo o podríamos mostrar el tiempo restante empezando desde el primero por segundo y luego sumando progresivamente el promedio hasta 10 últimos por segundo

Espero que mis pensamientos "nerviosos" ayuden a alguien a construir algo satisfactorio


¡Me sorprende que nadie haya respondido esta pregunta con código!

La forma simple de calcular el tiempo, según la respuesta de @JoshBerke, se puede codificar de la siguiente manera:

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 ... }

Este simple ejemplo funciona muy bien para el cálculo de progreso simple.
Sin embargo, para una tarea más complicada, ¡hay muchas maneras en que se puede mejorar este cálculo!

Por ejemplo, cuando está descargando un archivo grande, la velocidad de descarga podría fluctuar fácilmente. Para calcular la "ETA" más precisa, un buen algoritmo sería considerar solo los últimos 10 segundos de progreso. ¡Consulte ETACalculator.cs para una implementación de este algoritmo!

ETACalculator.cs es de Progression , una biblioteca de código abierto que escribí. Define una estructura muy fácil de usar para todo tipo de "cálculo de progreso". Hace que sea fácil tener pasos anidados que informan diferentes tipos de progreso. Si le preocupa el rendimiento percibido (como lo sugirió @JoshBerke), lo ayudará inmensamente.


Asegúrese de administrar el rendimiento percibido .

Aunque todas las barras de progreso tomaron exactamente la misma cantidad de tiempo en la prueba, dos características hicieron que los usuarios pensaran que el proceso era más rápido, incluso si no lo era:

  1. barras de progreso que se movieron suavemente hacia la finalización
  2. barras de progreso que aceleraron hacia el final

Por qué no?

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

TimeLeft se expresará en la unidad de tiempo timeTaken .

Editar:

Gracias por el comentario, tienes razón, debería ser:

(TimeTaken / linesProcessed) * linesLeft = timeLeft

entonces tenemos

(10 / 100) * 200 = 20 segundos ahora pasan 10 segundos
(20 / 100) * 200 = 40 segundos restantes ahora 10 segundos más y procesamos 100 líneas más
(30 / 200) * 100 = 15 segundos y ahora todos vemos por qué el diálogo de archivo de copia salta de 3 horas a 30 minutos :-)


No para revivir una pregunta muerta, pero seguí volviendo para hacer referencia a esta página.
Podría crear un método de extensión en la clase Cronómetro para obtener funcionalidades que obtendrían un lapso de tiempo estimado estimado.

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://.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; } }

Ejemplo:

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()); }

Con suerte, será de alguna utilidad para alguien.


EDITAR: Se debe tener en cuenta que esto es más preciso cuando cada ciclo toma la misma cantidad de tiempo.
Editar 2: en lugar de crear subclases, creé un método de extensión.


Qué tal esto....

Lo usé para recorrer un conjunto de registros (filas en un archivo de Excel, en un caso)

L es el número de fila actual X es el número total de filas dat_Start está establecido en Ahora () cuando comienza la rutina

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")


Hice esto y funciona bastante bien, puede cambiar la firma del método de acuerdo con sus tipos de variables o también con el tipo de devolución, probablemente le gustaría obtener el objeto TimeSpan o solo los segundos ...

/// <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(); }

Tendrá que inicializar una variable DateTime cuando comience el procesamiento y enviarla al método en cada iteración.

No olvide que probablemente su ventana estará bloqueada si el proceso es bastante largo, por lo que cuando coloque el valor devuelto en un control, no olvide utilizar el método .Refresh() .

Si está utilizando subprocesos, entonces puede intentar establecer el texto utilizando el método Invoke(Action) , sería más fácil usar este método de extensión para archivarlo fácilmente.

Si usa una aplicación de consola, entonces no debería tener problemas para mostrar la línea de salida.

Espero que ayude a alguien.