¿Hay una función en la que convertirá los nanosegundos en un std :: string, decir algo como "3m12s"?
No.Pero te mostraré cómo puedes hacer esto fácilmente a continuación.
¿Debo usar el std :: crono :: :: steady_clock ahora() cada vez que actualizo mi barra de progreso, y restar que a partir de _begin para determinar TIME_LEFT?
Sí.
¿Hay un mejor algoritmo para determinar TIME_LEFT
Sí. Vea abajo.
Editar
había mal interpretado originalmente "ticks" como "reloj de garrapatas", cuando en realidad "garrapatas" tiene unidades de trabajo y _ticks_occurred/_total_ticks
puede interpretarse como% JOB_DONE. Así que he cambiado la propuesta progress_bar
a continuación según corresponda.
creo que la ecuación:
time_left = (time_taken/_total_ticks) * (_total_ticks - _ticks_occured)
es incorrecto. No pasa un control de cordura: si _ticks_occured == 1
y _total_ticks
es grande, entonces time_left
es aproximadamente igual (vale, un poco menos) time_taken
. Eso no tiene sentido.
estoy reescribiendo la ecuación anterior sea:
time_left = time_taken * (1/percent_done - 1)
donde
percent_done = _ticks_occurred/_total_ticks
Ahora, como percent_done
se aproxima a cero, time_left
tiende a infinito, y cuando percent_done
se aproxima a 1, 'time_left
se aproxima a 0. Cuando percent_done
es 10%, time_left
es 9*time_taken
. Esto cumple mis expectativas, asumiendo un costo de tiempo aproximadamente lineal por turno de trabajo.
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), _ticks_occurred(0),
_begin(std::chrono::steady_clock::now())
// ...
{}
void tick()
{
using namespace std::chrono;
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
// somehow _ticks_occurred is updated here and is not zero
duration time_taken = Clock::now() - _begin;
float percent_done = (float)_ticks_occurred/_total_ticks;
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
minutes minutes_left = duration_cast<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::duration duration;
typedef Clock::rep rep;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
Tráfico en std :: chrono :: duraciones siempre que pueda. De esa manera, <chrono>
realiza todas las conversiones por usted. typedefs puede facilitar la escritura con los nombres largos. Y dividir el tiempo en minutos y segundos es tan fácil como se muestra arriba.
Como bames53 notas en su respuesta, si desea utilizar mi instalación <chrono_io>
, es genial también. Sus necesidades pueden ser lo suficientemente simples como para no querer. Es una llamada de juicio. La respuesta de bames53 es una buena respuesta. Pensé que estos detalles adicionales podrían ser útiles también.
Editar
accidentalmente me dejó un error en el código de seguridad. Y en lugar de simplemente parchear el código anterior, pensé que sería una buena idea señalar el error y mostrar cómo usar <chrono>
para solucionarlo.
El error está aquí:
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
y aquí:
typedef Clock::duration duration;
En la práctica steady_clock::duration
se basa por lo general en un tipo entero. <chrono>
llama esto al rep
(abreviatura de representación). Y cuando percent_done
es mayor que 50%, el factor multiplicado por time_taken
va a ser menor que 1. Y cuando rep
es integral, eso se convierte en 0. Entonces este progress_bar
solo se comporta bien durante el primer 50% y predice 0 izquierda durante el último 50%.
La clave para solucionar esto es traficar en duration
s que se basan en coma flotante en lugar de enteros. Y <chrono>
hace que esto sea muy fácil de hacer.
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
duration
tiene ahora el mismo período garrapata tan steady_clock::duration
pero utiliza un float
para la representación. Y ahora el cálculo para time_left
puede dejar fuera de la static_cast:
duration time_left = time_taken * (1/percent_done - 1);
Aquí está todo el paquete de nuevo con estas soluciones:
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), _ticks_occurred(0),
_begin(std::chrono::steady_clock::now())
// ...
{}
void tick()
{
using namespace std::chrono;
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
// somehow _ticks_occurred is updated here and is not zero
duration time_taken = Clock::now() - _begin;
float percent_done = (float)_ticks_occurred/_total_ticks;
duration time_left = time_taken * (1/percent_done - 1);
minutes minutes_left = duration_cast<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n";
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
Nada como un poco de pruebas ... ;-)
El motivo del "tic" es representar el progreso, es decir: tengo 1,000,000 de operaciones (ticks) para completar. Por lo que puedo decir, boost tiene un 'chrono_io'. ¿Recomendarías usar eso? – nerozehl
Oh, "tic" representa una unidad de trabajo, no una unidad de tiempo? Si es así, no entiendo bien tu pregunta. Leí por error "tic del reloj". El impulso '' es una copia autorizada de mi ''. Debería estar bien usarlo si lo encuentra útil. Estoy proponiendo '' para un estándar futuro, por lo que sería bueno tener comentarios al respecto. –
Sí, tick siendo una unidad de trabajo ... Supuse que debería haber sido más claro, lo siento por los problemas en eso. ¡Muchas gracias! :) – nerozehl