timeit与时间装饰器

我正在尝试一些代码。 首先我使用了定时装饰器:

#!/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.) 

产量

 % test.py time_indexing took 73.230ms. time_izip took 122.057ms. 

在这里我使用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 

使用timeit结果几乎是一样的,但是使用定时装饰器, time_indexingtime_izip快。

这个区别是什么造成的?

任何一种方法都应该相信?

如果是这样,哪个?

使用时间。 不止一次地运行testing给了我更好的结果。

 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. 

使用从functools包装改善马特·阿尔科克的答案。

 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 

在一个例子中:

 @timing def f(a): for _ in range(a): i = 0 return -1 

@timing包装调用方法f

 func:'f' args:[(100000000,), {}] took: 14.2240 sec f(100000000) 

这样做的好处是它保留了原始function的属性; 也就是说,像函数名和docstring这样的元数据在返回的函数中被正确地保存了。

我会使用定时装饰器,因为您可以使用批注来散布代码周围的时间,而不是使您的代码与时序逻辑混乱。

 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 

使用装饰器很容易使用注释。

 @timeit def compute_magic(n): #function definition #.... 

或者重新定义你想要的function。

 compute_magic = timeit(compute_magic) 

我厌倦了from __main__ import foo ,现在使用这个 – 为简单的参数,%r工作,而不是在Ipython。
(为什么timeit只适用于string,而不是thunk / closures,即timefunc(f,任意参数)?)

 import timeit def timef( funcname, *args, **kwargs ): """ timeit a func with args, eg 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 __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", """ ab """ ) timef( "f", 1, 2 ) timef( "f", x=3 ) timef( "f", x=3 ) timef( "f", 1, 2, x=3, y=4 ) 

补充:另请参阅“ipython与主要玩奇怪的技巧”,马尔泰利在运行doctests通过ipython

只是一个猜测,但差异可能是范围()值差异的数量级?

从您的原始来源:

 alist=range(1000000) 

从你的时间例子来看:

 alist=range(100000) 

对于它的价值,这里是我的系统上的范围设置为100万的结果:

 $ 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 

我无法让你的其他代码运行,因为我无法导入我的系统上的“装饰”模块。


更新 – 我看到,当我运行你的代码没有涉及装饰相同的差异。

 $ ./test.py time_indexing took 84.846ms. time_izip took 132.574ms. 

感谢张贴这个问题; 今天我学到了一些东西 =)

不pipe这个特别的练习,我会想象使用timeit是更安全可靠的select。 它也是跨平台的,不像你的解决scheme。