Python 如何使用timeit模块
我理解Python 如何使用timeit模块,python,time,timeit,Python,Time,Timeit,我理解timeit的概念,但我不确定如何在我的代码中实现它 如何将两个函数(例如insertion\u sort和tim\u sort)与timeit进行比较?我发现使用timeit最简单的方法是从命令行: 给定测试.py: def InsertionSort(): ... def TimSort(): ... 运行时间如下所示: % python -mtimeit -s'import test' 'test.InsertionSort()' % python -mtimeit -s'impo
timeit
的概念,但我不确定如何在我的代码中实现它
如何将两个函数(例如
insertion\u sort
和tim\u sort
)与timeit
进行比较?我发现使用timeit最简单的方法是从命令行:
给定测试.py:
def InsertionSort(): ...
def TimSort(): ...
运行时间如下所示:
% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
其工作方式是运行一次安装程序代码,然后重复调用一系列语句。因此,如果您想测试排序,则需要谨慎,以便就地排序的一次传递不会影响已排序数据的下一次传递(当然,这将使排序真正出色,因为当数据已部分排序时,它的性能最佳)
以下是如何设置排序测试的示例:
>>> import timeit
>>> setup = '''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''
>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145
请注意,该系列语句在每次传递时都会生成未排序数据的新副本
另外,请注意七次运行度量套件并只保留最佳时间的计时技术——这确实有助于减少系统上运行的其他进程导致的度量失真
这些是我正确使用timeit的技巧。希望这有帮助:-)如果您想在交互式Python会话中使用
timeit
,有两个方便的选项:
%timeit
特殊功能:
In [1]: def f(x):
...: return x*x
...:
In [2]: %timeit for x in range(100): f(x)
100000 loops, best of 3: 20.3 us per loop
\uuuuu main\uuuu
导入函数和之前在交互式会话中定义的其他名称来访问它们:
>>> def f(x):
... return x * x
...
>>> import timeit
>>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
number=100000)
[2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
我要告诉你一个秘密:使用
timeit
的最好方法是在命令行上
在命令行上,timeit
进行适当的统计分析:它告诉您最短的运行时间。这是好的,因为所有的计时错误都是正的。所以最短的时间误差最小。没有办法得到负误差,因为计算机的计算速度永远不会超过它的计算速度
因此,命令行界面:
%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop
这很简单,嗯
您可以设置以下内容:
%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop
这也很有用
如果需要多行,可以使用shell的自动延续或使用单独的参数:
%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop
这提供了一个
x = range(1000)
y = range(100)
和时代
sum(x)
min(y)
如果您想拥有更长的脚本,可能会尝试在Python脚本中移动到
timeit
。我建议避免这样做,因为在命令行上进行分析和计时会更好。相反,我倾向于制作shell脚本:
SETUP="
... # lots of stuff
"
echo Minmod arr1
python -m timeit -s "$SETUP" "Minmod(arr1)"
echo pure_minmod arr1
python -m timeit -s "$SETUP" "pure_minmod(arr1)"
echo better_minmod arr1
python -m timeit -s "$SETUP" "better_minmod(arr1)"
... etc
由于多次初始化,这可能需要更长的时间,但通常这不是什么大问题
但是如果您想在模块中使用
timeit
,该怎么办
简单的方法是:
def function(...):
...
timeit.Timer(function).timeit(number=NUMBER)
这会给你累计(而不是最短!)的时间来运行这个次数
要获得良好的分析,请使用。重复,并取最小值:
min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))
通常应将其与functools.partial
而不是lambda:…
结合使用,以降低开销。因此,您可能会有如下情况:
from functools import partial
def to_time(items):
...
test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)
# Divide by the number of repeats
time_taken = min(times) / 1000
您还可以执行以下操作:
timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)
这将使您从命令行中获得更接近界面的东西,但方式要冷淡得多。“从主导入…”
允许您在由timeit
创建的人工环境中使用主模块中的代码
值得注意的是,这是一个方便的Timer(…).timeit(…)
包装器,因此并不特别擅长计时。我个人更喜欢使用计时器(…)。重复(…)
,如上所示
警告
timeit
中有一些警告无处不在
- 间接费用不计入。假设您要计算时间
x+=1
,以了解添加所需的时间:
>>> python -m timeit -s "x = 0" "x += 1"
10000000 loops, best of 3: 0.0476 usec per loop
这不是0.0476µs。你只知道比这少。所有的错误都是肯定的
因此,请尝试寻找纯开销:
>>> python -m timeit -s "x = 0" ""
100000000 loops, best of 3: 0.014 usec per loop
>>> python -m timeit -s "x = 0" "x"
100000000 loops, best of 3: 0.0166 usec per loop
这是一个很好的30%开销,仅从时间上看!这会严重扭曲相对计时。但你真正关心的只是增加时间;x
的查找时间也需要包含在开销中:
>>> python -m timeit -s "x = 0" ""
100000000 loops, best of 3: 0.014 usec per loop
>>> python -m timeit -s "x = 0" "x"
100000000 loops, best of 3: 0.0166 usec per loop
差别不大,但确实存在
- 变异方法是危险的
>>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
10000000 loops, best of 3: 0.0436 usec per loop
但那是完全错误的x
是第一次迭代后的空列表。您需要重新初始化:
>>> python -m timeit "x = [0]*100000" "while x: x.pop()"
100 loops, best of 3: 9.79 msec per loop
但是你有很多开销。请分别说明这一点
>>> python -m timeit "x = [0]*100000"
1000 loops, best of 3: 261 usec per loop
注意,这里减去开销是合理的,因为开销只是时间的一小部分
对于您的示例,值得注意的是,对于已经排序的列表,插入排序和Tim排序都具有完全不寻常的计时行为。这意味着您需要在排序之间使用random.shuffle
,以避免破坏计时
如果要快速比较两个代码块/函数,可以执行以下操作:
import timeit
start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
让我们在以下每一项中设置相同的字典,并测试执行时间
setup参数基本上是设置字典
数字是运行代码1000000次。不是设置,而是stmt
当您运行这个程序时,您可以看到索引比get快得多。您可以运行多次以查看
代码基本上是试图在字典中获取c的值
import timeit
print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
这是我的结果,你的结果会有所不同
按指数:0.20900007452246427
通过get:0.54841166886888内置的timeit模块在IPython命令行中工作得最好
# Генерация целых чисел
def gen_prime(x):
multiples = []
results = []
for i in range(2, x+1):
if i not in multiples:
results.append(i)
for j in range(i*i, x+1, i):
multiples.append(j)
return results
import timeit
# Засекаем время
start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)
# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)
要从模块内为功能计时,请执行以下操作:
from timeit import default_timer as timer
import sys
def timefunc(func, *args, **kwargs):
"""Time a function.
args:
iterations=3
Usage example:
timeit(myfunc, 1, b=2)
"""
try:
iterations = kwargs.pop('iterations')
except KeyError:
iterations = 3
elapsed = sys.maxsize
for _ in range(iterations):
start = timer()
result = func(*args, **kwargs)
elapsed = min(timer() - start, elapsed)
print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
return result
如何将Python REPL解释器与接受参数的函数一起使用的示例
>>> import timeit
>>> def naive_func(x):
... a = 0
... for i in range(a):
... a += i
... return a
>>> def wrapper(func, *args, **kwargs):
... def wrapper():
... return func(*args, **kwargs)
... return wrapper
>>> wrapped = wrapper(naive_func, 1_000)
>>> timeit.timeit(wrapped, number=1_000_000)
0.4458435332577161
这非常有效:
python -m timeit -c "$(cat file_name.py)"
只需将整个代码作为timeit的参数传递:
import timeit
print(timeit.timeit(
"""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
"""
, number=10))
对我来说,这是最快的方式:
import timeit
def foo():
print("here is my code to time...")
timeit.timeit(stmt=foo, number=1234567)
您将创建两个funct