tag recommendation moz metadescription length descriptions description go time

recommendation - Medir correctamente la duración del tiempo en Go



tag meta description (3)

Tiempo de paquete

Relojes monotónicos

Los sistemas operativos proporcionan tanto un "reloj de pared", que está sujeto a cambios en la sincronización del reloj, como un "reloj monotónico", que no lo está. La regla general es que el reloj de pared es para indicar la hora y el reloj monotónico para medir el tiempo. En lugar de dividir la API, en este paquete el Tiempo devuelto por el tiempo. Ahora contiene una lectura de reloj de pared y una lectura de reloj monotónica; las operaciones posteriores de tiempo usan la lectura del reloj de pared, pero las operaciones posteriores de medición del tiempo, específicamente comparaciones y restas, usan la lectura del reloj monotónico.

Por ejemplo, este código siempre calcula un tiempo transcurrido positivo de aproximadamente 20 milisegundos, incluso si se cambia el reloj de pared durante la operación que se está cronometrando:

start := time.Now() ... operation that takes 20 milliseconds ... t := time.Now() elapsed := t.Sub(start)

Otros modismos, como time.Since (start), time.Till (deadline) y time.Now (). Before (deadline), son igualmente robustos contra los reinicios del reloj de pared.

Comenzando con Go 1.9 (publicado el 24 de agosto de 2017), Go usa un reloj monotónico para las duraciones.

Ver Propuesta: Mediciones de tiempo transcurrido monotónico en Go .

¿Cuál es la forma correcta de medir con precisión una duración de tiempo en Go? La mayoría de las aplicaciones solo usan el paquete de tiempo estándar y el siguiente enfoque:

var startTime = time.Now() doSomeHardWork() var duration = time.Since(startTime) // or: time.Now() - startTime

Sin embargo, time.Now() devuelve la hora actual del sistema, lo que conduce a dos fallas:

  1. Si se cambia la hora del sistema durante la medición (por ejemplo, debido a un cambio de zona horaria (DST) o un segundo de salto ), la duración resultante también es incorrecta.
  2. La hora del sistema puede marcar deliberadamente más rápido o más lento que el tiempo real. Esto siempre sucede cuando el sistema operativo sincroniza el reloj interno con los servidores de hora NTP (¡lo que puede suceder varias veces por hora!)

    Desde MSDN :

    [El servicio de hora] ajusta la velocidad del reloj local para permitir que converja hacia la hora correcta. Si la diferencia de tiempo entre el reloj local y la [muestra exacta de la hora] es demasiado grande para corregirla ajustando la velocidad del reloj local, el servicio de hora ajusta el reloj local a la hora correcta.

Si la hora del sistema cambia (ya sea manualmente o debido a DST), es posible detectar la duración no válida y descartarla. Pero si el reloj del sistema funciona, por ejemplo, un 10% más rápido para sincronizarse con la hora mundial, es prácticamente imposible de detectar. Ese es el comportamiento previsto y cómo se diseña el reloj del sistema.

Por esa razón, la mayoría de los otros idiomas ofrecen una API dedicada para medir las duraciones:

¿Cuál es la forma correcta de medir con precisión el tiempo de ejecución en Go?


Esto está disponible en Go 1.9 (agosto de 2017) con relojes monotónicos, no tendrá que hacer nada especial para beneficiarse de ello:

https://tip.golang.org/pkg/time/#hdr-Monotonic_Clocks

Los sistemas operativos proporcionan tanto un "reloj de pared", que está sujeto a cambios en la sincronización del reloj, como un "reloj monotónico", que no lo está. La regla general es que el reloj de pared es para indicar la hora y el reloj monotónico para medir el tiempo. En lugar de dividir la API, en este paquete el Tiempo devuelto por el tiempo. Ahora contiene una lectura de reloj de pared y una lectura de reloj monotónica; las operaciones posteriores de tiempo usan la lectura del reloj de pared, pero las operaciones posteriores de medición del tiempo, específicamente comparaciones y restas, usan la lectura del reloj monotónico.

Por ejemplo, este código siempre calcula un tiempo transcurrido positivo de aproximadamente 20 milisegundos, incluso si se cambia el reloj de pared durante la operación que se está cronometrando:

start := time.Now() ... operation that takes 20 milliseconds ... t := time.Now() elapsed := t.Sub(start)

Otros modismos, como time.Since (start), time.Till (deadline) y time.Now (). Before (deadline), son igualmente robustos contra los reinicios del reloj de pared.

Este cambio en el time pkg se desencadenó por este issue , lo que provocó esta proposal de cambio de Russ Cox:

Comparación y resta de los tiempos observados por el tiempo. Ahora puede devolver resultados incorrectos si el reloj de la pared del sistema se reinicia entre las dos observaciones. Proponemos extender el tiempo. Representación de tiempo para mantener una lectura de reloj monotónica adicional para usar en esos cálculos. Entre otros beneficios, esto debería hacer que sea imposible realizar una medición básica del tiempo transcurrido utilizando el tiempo. Ahora y el tiempo. Desde que se informa una duración negativa u otro resultado no basado en la realidad.


Para Go 1.8 y anteriores, la función de sincronización correcta no está dentro del paquete de tiempo, sino en el paquete de tiempo de ejecución :

func nanotime() int64

Para medir correctamente el tiempo de ejecución, se debe utilizar el siguiente procedimiento:

var startTime = runtime.nanotime() doSomeHardWork() var duration = runtime.nanotime() - startTime

Desafortunadamente, el método en sí no está muy bien documentado. Surgió en este tema después de una issue . Para Go 1.9 y más reciente, consulte la respuesta de Kenny Grant.