J'essaie de chronométrer du code. J'ai d'abord utilisé un décorateur de chronométrage:
#!/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.)
les rendements
% test.py
time_indexing took 73.230ms.
time_izip took 122.057ms.
Et ici j'utilise 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
En utilisant timeit, les résultats sont pratiquement les mêmes, mais en utilisant le décorateur de synchronisation, il apparaît time_indexing
est plus rapide que time_izip
.
Qu'est-ce qui explique cette différence?
Faut-il croire à l'une ou l'autre méthode?
Si oui, lequel?
Utilisez timeit. Faire plusieurs fois le test me donne de bien meilleurs résultats.
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.
Utilisez l'habillage de functools
pour améliorer la réponse 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
Dans un exemple:
@timing
def f(a):
for _ in range(a):
i = 0
return -1
Appel de la méthode f
encapsulée avec @timing
:
func:'f' args:[(100000000,), {}] took: 14.2240 sec
f(100000000)
L'avantage de ceci est qu'il préserve les attributs de la fonction d'origine; c'est-à-dire que les métadonnées comme le nom de la fonction et la docstring sont correctement conservées sur la fonction renvoyée.
J'utiliserais un décorateur de synchronisation, car vous pouvez utiliser des annotations pour saupoudrer la synchronisation autour de votre code plutôt que de vous compliquer le code avec la logique de synchronisation.
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
L'utilisation du décorateur est facile, soit utilisez des annotations.
@timeit
def compute_magic(n):
#function definition
#....
Ou renommez la fonction que vous souhaitez chronométrer.
compute_magic = timeit(compute_magic)
Je me suis lassé de from __main__ import foo
, utilisez maintenant ceci - pour des arguments simples, pour lesquels% r fonctionne, et non en Ipython.
(Pourquoi timeit
ne fonctionne que sur les chaînes, pas sur les thunks/closures, c'est-à-dire timefunc (f, arguments arbitraires)?)
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 Stackoverflow
"""
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 __== "__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 )
Ajouté: voir aussi "ipython joue des tours bizarres avec main ", Martelli dans running-doctests-through-ipython
Juste une supposition, mais la différence pourrait-elle être de l'ordre de grandeur de la différence dans les valeurs range ()?
De votre source d'origine:
alist=range(1000000)
À partir de votre exemple timeit
:
alist=range(100000)
Pour ce que ça vaut, voici les résultats sur mon système avec la plage définie à 1 million:
$ 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
Je n'ai pas pu faire fonctionner votre autre code, car je n'ai pas pu importer le module "décorateur" sur mon système.
pdate - Je vois la même différence que vous faites lorsque j'exécute votre code sans le décorateur impliqué.
$ ./test.py
time_indexing took 84.846ms.
time_izip took 132.574ms.
Merci d'avoir posté cette question; J'ai appris quelque chose aujourd'hui. =)
indépendamment de cet exercice particulier, j'imagine que l'utilisation de timeit
est une option beaucoup plus sûre et fiable. il est également multiplateforme, contrairement à votre solution.