Medición del tiempo transcurrido en python

¿Existe una forma / módulo simple para medir correctamente el tiempo transcurrido en python? Sé que simplemente puedo llamar a time.time() dos veces y tomar la diferencia, pero eso dará resultados erróneos si se cambia la hora del sistema. Por supuesto, eso no sucede muy a menudo, pero sí indica que estoy midiendo algo incorrecto.

Usar time.time() para medir duraciones es increíblemente indirecto cuando lo piensas. Usted toma la diferencia de dos mediciones de tiempo absoluto que, a su vez, se construyen a partir de mediciones de duración (realizadas por temporizadores) y tiempos absolutos conocidos (establecidos manualmente o mediante ntp), en los que no está interesado en absoluto.

Entonces, ¿hay alguna forma de consultar este “tiempo del temporizador” directamente? Me imagino que se puede representar como un valor de milisegundos o microsegundos que no tiene una representación absoluta significativa (y, por lo tanto, no necesita ajustarse con la hora del sistema). Mirando alrededor un poco, parece que esto es exactamente lo que hace System.nanoTime() en Java, pero no encontré una función Python correspondiente, aunque debería ser (más fácil que técnicamente) proporcionar que time.time() .

Editar: Para evitar confusiones y responder a las respuestas a continuación: Esto no se trata de cambios de horario de verano, y tampoco quiero el tiempo de CPU, quiero el tiempo físico transcurrido. No necesita ser muy detallado, ni siquiera particularmente preciso. Simplemente no debería darme duraciones negativas, o duraciones que están desactivadas por varios órdenes de magnitud (por encima de la granularidad), simplemente porque alguien decidió ajustar el reloj del sistema a un valor diferente. Esto es lo que dicen los documentos de Python sobre ‘time.time ()’:

“Si bien esta función normalmente devuelve valores no decrecientes, puede devolver un valor más bajo que una llamada previa si el reloj del sistema se ha establecido entre las dos llamadas”

Esto es exactamente lo que quiero evitar, ya que puede llevar a cosas extrañas como valores negativos en los cálculos de tiempo. Puedo solucionar este problema en este momento, pero creo que es una buena idea aprender a usar las soluciones adecuadas cuando sea posible, ya que los errores volverán a morderlo un día.

Edit2: Algunas investigaciones muestran que puede obtener una medición independiente del tiempo del sistema como la que quiero en Windows mediante el uso de GetTickCount64 (), bajo Linux puede obtenerlo en el valor de retorno de times (). Sin embargo, todavía no puedo encontrar un módulo que proporcione esta funcionalidad en Python.

Lo que parece estar buscando es un temporizador monotónico . Una referencia de tiempo monótona no salta ni retrocede.

Ha habido varios bashs de implementar un reloj monotómico multiplataforma para Python basado en la referencia del sistema operativo. (Windows, POSIX y BSD son bastante diferentes) Vea las discusiones y algunos de los bashs de tiempo monotónico en esta publicación SO .

Sobre todo, puedes usar os.times ():

os.times ()

Devuelva una tupla de 5 números de punto flotante que indican los tiempos acumulados (procesador u otros), en segundos. Los elementos son: tiempo del usuario, tiempo del sistema, tiempo del usuario de los niños, tiempo del sistema de los niños y tiempo real transcurrido desde un punto fijo en el pasado, en ese orden. Consulte los tiempos de la página del manual de Unix (2) o la documentación correspondiente de la API de la plataforma Windows. En Windows, solo se llenan los dos primeros elementos, los otros son cero.

Disponibilidad: Unix, Windows

Pero eso no completa el tiempo real transcurrido necesario (la quinta tupla) en Windows.

Si necesita soporte de Windows, considere ctypes y puede llamar a GetTickCount64 () directamente, como se ha hecho en esta receta .

Para medir el tiempo de CPU transcurrido, mira time.clock () . Este es el equivalente del campo de tiempo de usuario de Linux () .

Para la evaluación comparativa, use timeit .

El módulo datetime , que forma parte de Python 2.3+ , también tiene microsegundos si es compatible con la plataforma.

Ejemplo:

 >>> import datetime as dt >>> n1=dt.datetime.now() >>> n2=dt.datetime.now() >>> (n2-n1).microseconds 678521 >>> (n2.microsecond-n1.microsecond)/1e6 0.678521 ie, it took me .678521 seconds to type the second n2= line -- slow >>> n1.resolution datetime.timedelta(0, 0, 1) 1/1e6 resolution is claimed. 

Si le preocupan los cambios de hora del sistema (desde DS -> ST), simplemente verifique el objeto devuelto por datetime. Probablemente, la hora del sistema podría tener un pequeño ajuste de un ajuste de referencia NTP . Esto debería ser controlado , y las correcciones se aplican gradualmente , pero los tiempos de sincronización de ntp pueden tener un efecto con referencias de tiempo muy pequeñas (milisegundas o microsec).

También puede hacer referencia a la función C de Alex Martelli si desea algo de esa resolución. No iría demasiado lejos para reinventar la rueda. El tiempo exacto es básico y la mayoría de los sistemas operativos modernos hacen un buen trabajo.

Editar

Según sus aclaraciones, parece que necesita una comprobación lateral simple si el reloj del sistema ha cambiado. Solo compare con un servidor ntp local amigable:

 import socket import struct import time ntp="pool.ntp.org" # or whatever ntp server you have handy client = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) data = '\x1b' + 47 * '\0' client.sendto( data, ( ntp, 123 )) data, address = client.recvfrom( 1024 ) if data: print 'Response received from:', address t = struct.unpack( '!12I', data )[10] t -= 2208988800L #seconds since Epoch print '\tTime=%s' % time.ctime(t) 

NTP tiene una precisión de milisegundos en Internet y tiene una resolución de resolución de representación de 2 a 32 segundos (233 picosegundos). Debe ser lo suficientemente bueno?

Tenga en cuenta que la estructura de datos NTP de 64 bits se desbordará en 2036 y cada 136 años a partir de entonces , si realmente desea una solución robusta, compruebe mejor el desbordamiento …

Python 3.3 agregó un temporizador monotónico a la biblioteca estándar, que hace exactamente lo que estaba buscando. Gracias a Paddy3118 por señalar esto en “¿Cómo obtengo duraciones monotónicas en python?” .

 >>> import datetime >>> t1=datetime.datetime.utcnow() >>> t2=datetime.datetime.utcnow() >>> t2-t1 datetime.timedelta(0, 8, 600000) 

El uso de UTC evita esos períodos embarazosos cuando el reloj se desplaza debido al horario de verano.

En cuanto a usar un método alternativo en lugar de restar dos relojes, tenga en cuenta que el sistema operativo realmente contiene un reloj que se inicializa desde un reloj de hardware en la PC. Las implementaciones modernas del sistema operativo también mantendrán ese reloj sincronizado con alguna fuente oficial para que no se desvíe. Esto es mucho más preciso que cualquier temporizador de intervalo que la PC pueda estar ejecutando.

Las funciones de ejemplo que indica en su edición son dos cosas completamente diferentes:

  1. Linux times () devuelve los tiempos de proceso en milisegundos de CPU. El equivalente de Python es time.clock () o os.times() .
  2. Windows GetTickCount64 () devuelve el tiempo de actividad del sistema.

Aunque dos funciones diferentes, ambas (potencialmente) podrían usarse para revelar un reloj del sistema que tenía un “eructo” con estos métodos:

Primero:

Podría tomar tanto tiempo del sistema con time.time() como tiempo de CPU con time.clock() . Dado que el tiempo del reloj de pared SIEMPRE será mayor o igual al tiempo de CPU, descarte cualquier medida en la que el intervalo entre las dos lecturas time.time() sea ​​menor que las lecturas de verificación de time.clock() emparejadas.

Ejemplo:

 t1=time.time() t1check=time.clock() # your timed event... t2=time.time() t2check=time.clock() if t2-t1 < t2check - t1check: print "Things are rotten in Denmark" # discard that sample else: # do what you do with t2 - t1... 

Segundo:

Obtener el tiempo de actividad del sistema también es prometedor si le preocupa el reloj del sistema, ya que el restablecimiento del usuario no restablece el recuento de tics del tiempo de actividad en la mayoría de los casos. (Que yo sepa ...)

Ahora la pregunta más difícil: obtener el tiempo de actividad del sistema de una manera independiente de la plataforma, especialmente sin generar un nuevo shell, con la precisión de segundo segundo. Hmmm ...

Probablemente la mejor apuesta sea psutil . Al buscar la fuente , utilizan el uptime = GetTickCount() / 1000.00f; para Windows y sysctl "kern.boottime" para BSD / OS X, etc. Desafortunadamente, estos son todos de resolución de 1 segundo.

 from datetime import datetime start = datetime.now() print 'hello' end = datetime.now() delta = end-start print type(delta)  import datetime help(datetime.timedelta) ...elapsed seconds and microseconds...