– 测量小代码片段的执行时间 – 调试和分析(Python教程)(参考资料)
timeit
– 测量小代码片段的执行时间
源代码: Lib / timeit.py
这个模块提供了一种简单的方法来计算一小段Python代码。它有botha 命令行界面以及可调用一。它避免了一些测量执行时间的常见陷阱。参见Tim Peters对O’Reilly发表的PythonCookbook中“算法”一章的介绍.
基本实例
以下示例显示了命令行界面如何用于比较三个不同的表达式:
$ python3 -m timeit ""-".join(str(n) for n in range(100))"10000 loops, best of 5: 30.2 usec per loop$ python3 -m timeit ""-".join([str(n) for n in range(100)])"10000 loops, best of 5: 27.5 usec per loop$ python3 -m timeit ""-".join(map(str, range(100)))"10000 loops, best of 5: 23.2 usec per loop
这可以从 Python实现界面 with:
>>> import timeit>>> timeit.timeit(""-".join(str(n) for n in range(100))", number=10000)0.3018611848820001>>> timeit.timeit(""-".join([str(n) for n in range(100)])", number=10000)0.2727368790656328>>> timeit.timeit(""-".join(map(str, range(100)))", number=10000)0.23702679807320237
Python界面
模块定义了三个便捷函数和一个公共类:
timeit.
timeit
(stmt=”pass”, setup=”pass”, timer=<default timer>, number=1000000, globals=None)-
创建一个
Timer
实例给定的陈述,setup代码和timer函数并用timeit()
执行运行它的number方法。可选的globals参数指定一个命名空间,在其中执行code.更改版本3.5:可选globals参数被添加了
timeit.
repeat
(stmt=”pass”, setup=”pass”, timer=<default timer>, repeat=5, number=1000000, globals=None)-
用给定的陈述创建
Timer
实例,setup代码和timer使用给定的repeat()
count和repeat运行并运行number处决。可选的globals参数指定执行代码的anamespace.在版本3.5中更改:添加了可选的globals参数
在版本3.7中更改:默认值repeat从3变为5.
timeit.
default_timer
()-
默认计时器,总是
time.perf_counter()
.改版3.3:
time.perf_counter()
现在是默认的计时器.
- class
timeit.
Timer
(stmt=”pass”, setup=”pass”, timer=<timer function>, globals=None) -
小代码片段的定时执行速度等级.
构造函数接受一个定时语句,一个用于设置的附加语句和一个定时器函数。两个语句都默认为
"pass"
;定时器功能与平台有关(参见模块文件字符串).stmt和setup也可能包含多个以;
或换行符,只要它们不包含多行字符串文字。默认情况下,语句将在timeit的命名空间内执行;可以通过将命名空间传递给globals.要测量第一个语句的执行时间,请使用
timeit()
方法。repeat()
和autorange()
方法是方便的方法来调用timeit()
多次。执行时间setup被排除在整体定时执行运行之外
stmt和setup参数也可以采用可用参数调用的对象。这将在定时器函数中嵌入对它们的调用,然后由
timeit()
。请注意,由于额外的函数调用,在这种情况下,时间开销会略大一些.在版本3.5中更改:可选globals参数被添加了
timeit
(number=1000000)-
时间number执行主要声明。这将执行一次setupstatement,然后返回执行main语句多次所需的时间,以秒为单位测量为float。参数是循环次数,默认为一百万。主要语句,设置语句和使用的定时器函数传递给构造函数.
注意
默认情况下,
timeit()
暂时关闭垃圾收集在时间安排。这种方法的优点是可以使独立时间更具可比性。该缺点是GC可能是所测量功能性能的重要组成部分。如果是这样,可以重新启用GC作为setup字符串中的第一个句子。例如:timeit.Timer("for i in range(10): oct(i)", "gc.enable()").timeit()
autorange
(callback=None)-
自动确定调用的次数
timeit()
.这是一个调用
timeit()
重复,总时间\u003e = 0.2秒,返回最终(循环次数,循环次数所用的时间)。它叫timeit()
从序列1,2,5,10,20,50,……中增加的数字,直到所用的时间至少为0.2秒如果给出callback而不是
None
,它将被称为后续审判,有两个论点:callback(number, time_taken)
.新版本3.6.
repeat
(repeat=5, number=1000000)-
Call
timeit()
a几次这是一个方便的功能,叫
timeit()
反复,返回结果列表。第一个参数指定调用timeit()
的次数。第二个参数指定numbertimeit()
.的参数注意
很容易从结果向量计算平均值和标准偏差并报告这些偏差。但是,这不是很有用。在典型情况下,最低值给出了机器运行给定代码片段的速度的下限;结果向量中较高的值通常不是由Python的速度变化引起的,而是由于其他过程干扰了你的计时精度。所以结果的
min()
可能是你应该感兴趣的唯一数字。之后,您应该查看整个向量并应用常识而不是统计.更改版本3.7: repeat的默认值从3更改为5.
print_exc
(file=None)-
帮助从定时代码打印回溯.
典型使用:
t = Timer(...) # outside the try/excepttry: t.timeit(...) # or t.repeat(...)except Exception: t.print_exc()
优于标准回溯的优点是来源将显示编译模板中的行。可选的file参数指示发送回溯的地方;它默认为
sys.stderr
.
命令行界面
当从命令行调用程序时,使用以下形式:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
其中可以理解以下选项:
-n
N
,
--number
=N
-
执行’statement’多少次
-r
N
,
--repeat
=N
-
多少次重复计时器(默认5)
-s
S
,
--setup
=S
-
语句最初执行一次(默认
pass
)
-p
,
--process
-
测量处理时间,而不是挂钟时间,使用
time.process_time()
代替time.perf_counter()
,这是默认的3.3版本中的新功能
-u
,
--unit
=U
-
指定定时器输出的时间单位;可以选择nsec,usec,msec或sec
版本3.5中的新功能
-v
,
--verbose
-
打印原始计时结果;重复更多数字精确度
-h
,
--help
-
打印一条简短的用法信息并退出
可以通过将每一行指定为单独的语句参数来给出多行语句;通过在引用中引用参数并使用前导空格,可以缩进行。多 -s
选项的处理方式相同.
如果没有给出-n
,则通过试验连续10次计算合适的循环数,直到总时间至少为0.2秒.
default_timer()
测量可能受到在同一台机器上运行的其他程序的影响,因此在需要精确计时时最好的做法是重复几次计时并使用最佳时间。-r
选择对此有利;在大多数情况下,默认的5次重复可能就足够了。您可以使用time.process_time()
来测量CPU时间.
注意
执行pass语句会产生一定的基线开销。此处的代码不会尝试隐藏它,但您应该注意它。可以通过不带参数调用程序来测量baseline开销,并且它可能在Python版本之间有所不同.
示例
可以提供一个只在开头执行一次的setup语句:
$ python -m timeit -s "text = "sample string"; char = "g"" "char in text"5000000 loops, best of 5: 0.0877 usec per loop$ python -m timeit -s "text = "sample string"; char = "g"" "text.find(char)"1000000 loops, best of 5: 0.342 usec per loop
>>> import timeit>>> timeit.timeit("char in text", setup="text = "sample string"; char = "g"")0.41440500499993504>>> timeit.timeit("text.find(char)", setup="text = "sample string"; char = "g"")1.7246671520006203
使用Timer
类及其方法可以完成同样的操作:
>>> import timeit>>> t = timeit.Timer("char in text", setup="text = "sample string"; char = "g"")>>> t.timeit()0.3955516149999312>>> t.repeat()[0.40183617287970225, 0.37027556854118704, 0.38344867356679524, 0.3712595970846668, 0.37866875250654886]
以下示例显示如何计算包含多行的表达式。这里我们比较使用hasattr()
与try
/except
的成本来测试缺少的和当前的对象属性:
$ python -m timeit "try:" " str.__bool__" "except AttributeError:" " pass"20000 loops, best of 5: 15.7 usec per loop$ python -m timeit "if hasattr(str, "__bool__"): pass"50000 loops, best of 5: 4.26 usec per loop$ python -m timeit "try:" " int.__bool__" "except AttributeError:" " pass"200000 loops, best of 5: 1.43 usec per loop$ python -m timeit "if hasattr(int, "__bool__"): pass"100000 loops, best of 5: 2.23 usec per loop
>>> import timeit>>> # attribute is missing>>> s = """\... try:... str.__bool__... except AttributeError:... pass... """>>> timeit.timeit(stmt=s, number=100000)0.9138244460009446>>> s = "if hasattr(str, "__bool__"): pass">>> timeit.timeit(stmt=s, number=100000)0.5829014980008651>>>>>> # attribute is present>>> s = """\... try:... int.__bool__... except AttributeError:... pass... """>>> timeit.timeit(stmt=s, number=100000)0.04215312199994514>>> s = "if hasattr(int, "__bool__"): pass">>> timeit.timeit(stmt=s, number=100000)0.08588060699912603
要给timeit
模块访问你定义的函数,你可以传递setup参数,其中包含一个import语句:
def test(): """Stupid test function""" L = [i for i in range(100)]if __name__ == "__main__": import timeit print(timeit.timeit("test()", setup="from __main__ import test"))
另一个选项是传递globals()
到globals参数,这将导致代码在您当前的全局命名空间中执行。这比单独指定import更方便:
def f(x): return x**2def g(x): return x**4def h(x): return x**8import timeitprint(timeit.timeit("[func(42) for func in (f,g,h)]", globals=globals()))