2009-07-30 4 views
45

Quiero registrar cuánto tiempo lleva algo de tiempo real en la pared. Actualmente estoy haciendo esto:¿Cómo obtengo duraciones de tiempo monótonas en python?

startTime = time.time() 
someSQLOrSomething() 
print "That took %.3f seconds" % (time.time() - startTime) 

Pero eso va a fallar (resultados incorrectos) si el tiempo se ajusta mientras que la consulta SQL (o lo que sea) se está ejecutando.

No quiero solo compararlo. Quiero iniciar sesión en una aplicación en vivo para ver las tendencias en un sistema en vivo.

Quiero algo como clock_gettime (CLOCK_MONOTONIC, ...), pero en Python. Y preferiblemente sin tener que escribir un módulo C que llame a clock_gettime().

+6

Bueno, no se sabe muy bien cómo a menudo está realmente ajustado. Ejecuto NTP. Pero con un reloj mononótico no tendré que tropezar con cosas como el error de Oracle RAC donde reinició el sistema si el tiempo se ajustó al revés. Además de los pequeños ajustes de NTP, hay segundos intercalares que pueden avanzar y retroceder. – Thomas

+7

S.Lott: incorrecto. "Un segundo intercalar es un ajuste positivo o negativo de un segundo [...]". Es trivial mirar hacia arriba. Es la primera frase del artículo "Leap second" en Wikipedia. Entonces, cuando se agrega un segundo intercalado, NTP reajustará el tiempo del sistema hacia atrás (porque su sistema es rápido. No contó 23:59:60), lo que significa que una medición basada en time.time() puede ser negativa. Créanme, muchos servidores Oracle se reiniciaron debido al error que mencioné anteriormente los últimos años. Y acabo de utilizar Oracle como ejemplo donde algunos programas no pueden manejar reajustes de tiempo. – Thomas

+0

No sé por qué (sin parches) Oracle 10 hace eso. Simplemente lo hace, y Oracle (la compañía) lo confirma. – Thomas

Respuesta

71

Esa función es bastante simple que se puede utilizar para acceder a ella ctypes:

#!/usr/bin/env python 

__all__ = ["monotonic_time"] 

import ctypes, os 

CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h> 

class timespec(ctypes.Structure): 
    _fields_ = [ 
     ('tv_sec', ctypes.c_long), 
     ('tv_nsec', ctypes.c_long) 
    ] 

librt = ctypes.CDLL('librt.so.1', use_errno=True) 
clock_gettime = librt.clock_gettime 
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] 

def monotonic_time(): 
    t = timespec() 
    if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0: 
     errno_ = ctypes.get_errno() 
     raise OSError(errno_, os.strerror(errno_)) 
    return t.tv_sec + t.tv_nsec * 1e-9 

if __name__ == "__main__": 
    print monotonic_time() 
+0

Wow. Eliminar "self". y funcionó a la perfección. Muy impresionante. Requiere ctypes que es complemento para Python 2.4, pero funcionará muy bien. Gracias. – Thomas

+0

Ah, y CLOCK_MONOTONIC parece ser 4 en FreeBSD y 1 en Linux. – Thomas

+0

Buena solución. ¿Hay alguna razón por la que uses ctypes.pointer en lugar de ctypes.byref? – Kiv

8

Como se señaló en this question, evitando reajustes NTP en Linux requiere CLOCK_MONOTONIC_RAW. Eso se define como 4 en Linux (desde 2.6.28).

Portably obtener la constante correcta #definido en un encabezado C de Python es complicado; hay h2py, pero eso realmente no ayuda a obtener el valor en tiempo de ejecución.

+1

Creo que la respuesta elegida fue incorrecta y no me explicó los saltos, ver [mi comentario sobre él] (http://stackoverflow.com/questions/3657289/linux-clock-gettimeclock-monotonic-strange-non-monotonic-behavior#comment12057005_3657385). Tanto CLOCK_MONOTONIC como CLOCK_MONOTONIC_RAW son monótonas, y la única forma en que difieren es que la primera corrige la velocidad del reloj del hardware utilizando NTP. – Tobu

23

Ahora, en Python 3.3 usaría time.monotonic.

+0

En CPython, supongo que internamente utiliza 'CLOCK_MONOTONIC' y ** not **' CLOCK_MONOTONIC_RAW', y este último ni siquiera está disponible en Python 3.3. –

+0

@ABB: [el módulo '' time' conoce 'CLOCK_MONOTONIC_RAW'] (http://hg.python.org/cpython/file/e20f98a8ed71/Modules/timemodule.c#l1377) aunque no lo usa tan lejos como Puedo ver. Podrías [definir el reloj que lo usa a través de 'ctypes' incluso en Python 2.7] (https://gist.github.com/zed/5073409) – jfs

+0

Si estoy leyendo la documentación correctamente, parece que en Python 3.3 puedes obtener 'CLOCK_MONOTONIC_RAW' invocando' time.clock_gettime (time.CLOCK_MONOTONIC_RAW) ', que es genial, así que cuando lo usa para medir pequeños intervalos de tiempo, nunca se introduce un error cuando la red actualiza la hora mediante ajustes NTP (Network Time Protocol). Referencia de tiempo de Python: https://docs.python.org/3/library/time.html#time.CLOCK_MONOTONIC_RAW. <- NOTA: SOLO PARA UNIX/LINUX. Para Windows, simplemente llame a 'time.clock()', que ya tiene una resolución de microsegundos o mejor, ya que usa QueryPerformanceCounter(). –

0

time.monotonic() podría ser útil:

Return el valor (en fracciones de segundo) de un reloj monótona, es decir un reloj que no puede pasar hacia atrás. El reloj no se ve afectado por las actualizaciones del reloj del sistema. El punto de referencia del valor devuelto no está definido, por lo que solo la diferencia entre los resultados de llamadas consecutivas es válida.

1

Así es como tengo tiempo monótona en Python 2.7:

Instalar el monotonic paquete:

pip install monotonic 

Luego, en Python:

import monotonic; mtime = monotonic.time.time #now mtime() can be used in place of time.time() 

t0 = mtime() 
#...do something 
elapsed = mtime()-t0 #gives correct elapsed time, even if system clock changed. 
Cuestiones relacionadas