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.)
yields
% 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_indexing
似乎比 time_izip
更快。
造成这种差异的原因是什么?
应该相信任何一种方法吗?
如果有,是哪一个?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
使用 functools 中的包装来改进 Matt Alcock 的答案。
举个例子:
调用用
@timing
包裹的方法f
:这样做的好处是保留了原函数的属性;也就是说,函数名称和文档字符串等元数据被正确保留在返回的函数上。
Use wrapping from
functools
to improve Matt Alcock's answer.In an example:
Invoking method
f
wrapped with@timing
:The advantage of this is that it preserves attributes of the original function; that is, metadata like the function name and docstring is correctly preserved on the returned function.
我会使用计时装饰器,因为您可以使用注释在代码周围散布计时,而不是让您的代码因计时逻辑而变得混乱。
使用装饰器很容易或者使用注释。
或者为您想要计时的函数重新设置别名。
I would use a timing decorator, because you can use annotations to sprinkle the timing around your code rather than making you code messy with timing logic.
Using the decorator is easy either use annotations.
Or re-alias the function you want to time.
使用时间。多次运行测试给我带来了更好的结果。
->
Use timeit. Running the test more than once gives me much better results.
->
受到 Micah Smith 的回答的启发,我直接进行了有趣的打印(而不使用日志记录模块)。
下面方便在google colab使用。
Inspired by Micah Smith's answer, I made funcy print directly instead (and not use logging module).
Below is convenient for use at google colab.
我厌倦了
from __main__ import foo
,现在使用这个 -- 对于简单的参数,%r 可以工作,而不是在 Ipython 中。
(为什么
timeit
只适用于字符串,而不适用于thunks/闭包,即timefunc(f,任意args)?)添加:另请参阅“ipython与main玩奇怪的把戏”,马尔泰利
在运行-doctests-through-ipython
I got tired of
from __main__ import foo
, now use this -- for simple args, for which %r works,and not in Ipython.
(Why does
timeit
works only on strings, not thunks / closures i.e. timefunc( f, arbitrary args ) ?)Added: see also "ipython plays weird tricks with main", Martelli
in running-doctests-through-ipython
这就是您祈祷图书馆提供便携式解决方案的需求类型——DRY!幸运的是 funcy.log_durations 给出了答案。
从文档复制的示例:
浏览有趣的文档以了解其他变体,例如不同的关键字参数和
@log_iter_durations
。This is the type of need that you pray a library provides a portable solution -- DRY! Fortunately funcy.log_durations comes to the answer.
Example copied from documentation:
Browse the funcy documentation for other variants such as different keyword arguments and
@log_iter_durations
.这是一个适用于异步和同步函数的装饰器,并打印一个很好的人类可读输出,例如 8us、200ms 等...
这是一个 要点与此相同。
Here's a decorator that works for async and sync functions and prints a nice human readable output, e.g. 8us, 200ms, etc...
Here's a gist with the same.
只是猜测,但差异可能是 range() 值差异的数量级吗?
来自您的原始来源:
来自您的
timeit
示例:对于它的价值,这里是我的系统上的结果,范围设置为 100 万:
我无法让您的其他代码运行,因为我无法在我的系统上导入“装饰器”模块。
更新 - 当我在不涉及装饰器的情况下运行代码时,我看到了与您相同的差异。
感谢您提出这个问题;今天我学到了一些东西。 =)
Just a guess, but could the difference be the order of magnitude of difference in range() values?
From your original source:
From your
timeit
example:For what it's worth, here are the results on my system with the range set to 1 million:
I wasn't able to get your other code to run, since I could not import the "decorator" module on my system.
Update - I see the same discrepancy you do when I run your code without the decorator involved.
Thanks for posting this question; I learned something today. =)
不管这个特定的练习如何,我认为使用 timeit 是更安全和可靠的选择。与您的解决方案不同,它也是跨平台的。
regardless of this particular exercise, I'd imagine that using
timeit
is much safer and reliable option. it is also cross-platform, unlike your solution.