the program magick how code calculate python timing timeit

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.