resueltos - lista de funciones de python
Cronometraje preciso de las funciones en python (7)
Estoy programando en python en Windows y me gustaría medir con precisión el tiempo que tarda en ejecutarse una función. He escrito una función "time_it" que toma otra función, la ejecuta y devuelve el tiempo que tardó en ejecutarse.
def time_it(f, *args):
start = time.clock()
f(*args)
return (time.clock() - start)*1000
Llamo esto 1000 veces y promedie el resultado. (la constante 1000 al final es dar la respuesta en milisegundos).
Esta función parece funcionar, pero tengo la sensación molesta de que estoy haciendo algo mal, y que al hacerlo de esta manera estoy usando más tiempo del que realmente usa la función cuando está funcionando.
¿Hay una manera más estándar o aceptada de hacer esto?
Cuando cambié mi función de prueba para llamar a una impresión para que demore más, mi función time_it devuelve un promedio de 2.5 ms mientras que cProfile.run (''f ()'' regresa y promedia de 7.0 ms. Pensé que mi función sobreestimaría el tiempo en todo caso, ¿qué está pasando aquí?
Una nota adicional, es el tiempo relativo de funciones comparadas entre sí que me importa, no el tiempo absoluto ya que esto obviamente variará dependiendo del hardware y otros factores.
En lugar de escribir su propio código de creación de perfiles, le sugiero que consulte los perfiladores de Python incorporados ( profile
o profile
cProfile
, según sus necesidades): http://docs.python.org/library/profile.html
Este código es muy inexacto
total= 0
for i in range(1000):
start= time.clock()
function()
end= time.clock()
total += end-start
time= total/1000
Este código es menos inexacto
start= time.clock()
for i in range(1000):
function()
end= time.clock()
time= (end-start)/1000
El muy inexacto sufre de sesgo de medición si el tiempo de ejecución de la función es cercano a la precisión del reloj. La mayoría de los tiempos medidos son meramente números aleatorios entre 0 y unos pocos tics del reloj.
Dependiendo de la carga de trabajo de su sistema, el "tiempo" que observa desde una sola función puede ser completamente un artefacto de la programación del sistema operativo y otros gastos indirectos incontrolables.
La segunda versión (menos imprecisa) tiene menos sesgo de medición. Si su función es realmente rápida, puede necesitar ejecutarla 10.000 veces para amortiguar la programación del sistema operativo y otros gastos generales.
Ambos son, por supuesto, terriblemente engañosos. El tiempo de ejecución para su programa, como un todo, no es la suma de los tiempos de ejecución de la función. Solo puedes usar los números para comparaciones relativas. No son medidas absolutas que transmiten mucho significado.
Esto es más limpio
from contextlib import contextmanager
import time
@contextmanager
def timeblock(label):
start = time.clock()
try:
yield
finally:
end = time.clock()
print (''{} : {}''.format(label, end - start))
with timeblock("just a test"):
print "yippee"
Puede crear un decorador "timeme" como ese
import time
def timeme(method):
def wrapper(*args, **kw):
startTime = int(round(time.time() * 1000))
result = method(*args, **kw)
endTime = int(round(time.time() * 1000))
print(endTime - startTime,''ms'')
return result
return wrapper
@timeme
def func1(a,b,c = ''c'',sleep = 1):
time.sleep(sleep)
print(a,b,c)
func1(''a'',''b'',''c'',0)
func1(''a'',''b'',''c'',0.5)
func1(''a'',''b'',''c'',0.6)
func1(''a'',''b'',''c'',1)
Si desea sincronizar un método de python, incluso si el bloque que mide puede arrojar, un buen enfoque es usarlo with
instrucción. Definir alguna clase de Timer
como
import time
class Timer:
def __enter__(self):
self.start = time.clock()
return self
def __exit__(self, *args):
self.end = time.clock()
self.interval = self.end - self.start
Entonces quizás desee programar un método de conexión que pueda arrojar. Utilizar
import httplib
with Timer() as t:
conn = httplib.HTTPConnection(''google.com'')
conn.request(''GET'', ''/'')
print(''Request took %.03f sec.'' % t.interval)
__exit()__
método __exit()__
incluso si la solicitud de conexión falla. Más precisamente, harías que uses, try
finally
ver el resultado en caso de que arroje, como con
try:
with Timer() as t:
conn = httplib.HTTPConnection(''google.com'')
conn.request(''GET'', ''/'')
finally:
print(''Request took %.03f sec.'' % t.interval)
Similar a la respuesta de @ AlexMartelli
import timeit
timeit.timeit(fun, number=10000)
puede hacer el truco
Use el módulo timeit
de la biblioteca estándar de Python.
Uso básico:
from timeit import Timer
# first argument is the code to be run, the second "setup" argument is only run once,
# and it not included in the execution time.
t = Timer("""x.index(123)""", setup="""x = range(1000)""")
print t.timeit() # prints float, for example 5.8254
# ..or..
print t.timeit(1000) # repeat 1000 times instead of the default 1million