python - program - timeit versus decorador de tiempo
timeit pandas (6)
Independientemente de este ejercicio en particular, me imagino que usar timeit
es una opción mucho más segura y confiable. también es multiplataforma, a diferencia de su solución.
Estoy tratando de cronometrar un código. Primero usé un decorador de tiempo:
#!/usr/bin/env python
import time
from itertools import izip
from random import shuffle
def timing_val(func):
def wrapper(*arg, **kw):
''''''source: http://www.daniweb.com/code/snippet368.html''''''
t1 = time.time()
res = func(*arg, **kw)
t2 = time.time()
return (t2 - t1), res, func.__name__
return wrapper
@timing_val
def time_izip(alist, n):
i = iter(alist)
return [x for x in izip(*[i] * n)]
@timing_val
def time_indexing(alist, n):
return [alist[i:i + n] for i in range(0, len(alist), n)]
func_list = [locals()[key] for key in locals().keys()
if callable(locals()[key]) and key.startswith(''time'')]
shuffle(func_list) # Shuffle, just in case the order matters
alist = range(1000000)
times = []
for f in func_list:
times.append(f(alist, 31))
times.sort(key=lambda x: x[0])
for (time, result, func_name) in times:
print ''%s took %0.3fms.'' % (func_name, time * 1000.)
rendimientos
% test.py
time_indexing took 73.230ms.
time_izip took 122.057ms.
Y aquí uso Timeit:
% python - m timeit - s '''' ''alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]''
10 loops, best of 3:
64 msec per loop
% python - m timeit - s ''from itertools import izip'' ''alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]''
10 loops, best of 3:
66.5 msec per loop
Con timeit, los resultados son prácticamente los mismos, pero usando el decorador de sincronización aparece que time_indexing
es más rápido que time_izip
.
¿Qué explica esta diferencia?
¿Deberían creerse ambos métodos?
Si es así, ¿cuál?
Me cansé de from __main__ import foo
, ahora usa esto - para args simples, para las cuales% r funciona, y no en Ipython.
(¿Por qué timeit
funciona solo en cadenas, no en thunks / closures, es decir, timefunc (f, args arbitrarios)?)
import timeit
def timef( funcname, *args, **kwargs ):
""" timeit a func with args, e.g.
for window in ( 3, 31, 63, 127, 255 ):
timef( "filter", window, 0 )
This doesn''t work in ipython;
see Martelli, "ipython plays weird tricks with __main__" in
"""
argstr = ", ".join([ "%r" % a for a in args]) if args else ""
kwargstr = ", ".join([ "%s=%r" % (k,v) for k,v in kwargs.items()]) /
if kwargs else ""
comma = ", " if (argstr and kwargstr) else ""
fargs = "%s(%s%s%s)" % (funcname, argstr, comma, kwargstr)
# print "test timef:", fargs
t = timeit.Timer( fargs, "from __main__ import %s" % funcname )
ntime = 3
print "%.0f usec %s" % (t.timeit( ntime ) * 1e6 / ntime, fargs)
#...............................................................................
if __name__ == "__main__":
def f( *args, **kwargs ):
pass
try:
from __main__ import f
except:
print "ipython plays weird tricks with __main__, timef won''t work"
timef( "f")
timef( "f", 1 )
timef( "f", """ a b """ )
timef( "f", 1, 2 )
timef( "f", x=3 )
timef( "f", x=3 )
timef( "f", 1, 2, x=3, y=4 )
Agregado: vea también "ipython juega trucos extraños con main ", Martelli en running-doctests-through-ipython
Solo una suposición, pero ¿podría la diferencia ser el orden de magnitud de la diferencia en los valores de range ()?
De su fuente original:
alist=range(1000000)
De su ejemplo timeit
:
alist=range(100000)
Por lo que vale, aquí están los resultados en mi sistema con el rango establecido en 1 millón:
$ python -V
Python 2.6.4rc2
$ python -m timeit -s ''from itertools import izip'' ''alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]''
10 loops, best of 3: 69.6 msec per loop
$ python -m timeit -s '''' ''alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]''
10 loops, best of 3: 67.6 msec per loop
No pude ejecutar su otro código, ya que no pude importar el módulo "decorador" en mi sistema.
Actualización : Veo la misma discrepancia que cuando ejecuto el código sin la participación del decorador.
$ ./test.py
time_indexing took 84.846ms.
time_izip took 132.574ms.
Gracias por publicar esta pregunta; Aprendí algo hoy. =)
Usaría un decorador de tiempo, porque puedes usar anotaciones para rociar el tiempo alrededor de tu código en lugar de hacer que el código sea desordenado con la lógica de tiempo.
import time
def timeit(f):
def timed(*args, **kw):
ts = time.time()
result = f(*args, **kw)
te = time.time()
print ''func:%r args:[%r, %r] took: %2.4f sec'' % /
(f.__name__, args, kw, te-ts)
return result
return timed
Usar el decorador es fácil, ya sea usar anotaciones.
@timeit
def compute_magic(n):
#function definition
#....
O vuelve a alias la función que desea medir con el tiempo.
compute_magic = timeit(compute_magic)
Use timeit Ejecutar la prueba más de una vez me da resultados mucho mejores.
func_list=[locals()[key] for key in locals().keys()
if callable(locals()[key]) and key.startswith(''time'')]
alist=range(1000000)
times=[]
for f in func_list:
n = 10
times.append( min( t for t,_,_ in (f(alist,31) for i in range(n))))
for (time,func_name) in zip(times, func_list):
print ''%s took %0.3fms.'' % (func_name, time*1000.)
->
<function wrapper at 0x01FCB5F0> took 39.000ms.
<function wrapper at 0x01FCB670> took 41.000ms.
Utilice envoltura de functools
para mejorar la respuesta de Matt Alcock.
from functools import wraps
from time import time
def timing(f):
@wraps(f)
def wrap(*args, **kw):
ts = time()
result = f(*args, **kw)
te = time()
print ''func:%r args:[%r, %r] took: %2.4f sec'' % /
(f.__name__, args, kw, te-ts)
return result
return wrap
En un ejemplo:
@timing
def f(a):
for _ in range(a):
i = 0
return -1
Invocando el método f
envuelto con @timing
:
func:''f'' args:[(100000000,), {}] took: 14.2240 sec
f(100000000)
La ventaja de esto es que conserva los atributos de la función original; es decir, los metadatos como el nombre de la función y docstring se conservan correctamente en la función devuelta.