ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](trace.xhtml "trace --- Trace or track Python statement execution") | - [上一页](profile.xhtml "The Python Profilers") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python 标准库](index.xhtml) » - [调试和分析](debug.xhtml) » - $('.inline-search').show(0); | # [`timeit`](#module-timeit "timeit: Measure the execution time of small code snippets.") --- 测量小代码片段的执行时间 **源码:** [Lib/timeit.py](https://github.com/python/cpython/tree/3.7/Lib/timeit.py) \[https://github.com/python/cpython/tree/3.7/Lib/timeit.py\] - - - - - - 该模块提供了一种简单的方法来计算一小段 Python 代码的耗时。它有 [命令行界面](#timeit-command-line-interface) 以及一个 [可调用](#python-interface) 方法。它避免了许多用于测量执行时间的常见陷阱。另见 Tim Peters 对 O'Reilly 出版的 *Python Cookbook* 中“算法”章节的介绍。 ## 基本示例 以下示例显示了如何使用 [命令行界面](#timeit-command-line-interface) 来比较三个不同的表达式: ``` $ 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 接口](#python-interface) 实现 ``` >>> 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 ``` A callable can also be passed from the [Python 接口](#python-interface): ``` >>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000) 0.19665591977536678 ``` Note however that [`timeit()`](#timeit.timeit "timeit.timeit") will automatically determine the number of repetitions only when the command-line interface is used. In the [示例](#timeit-examples) section you can find more advanced examples. ## Python 接口 该模块定义了三个便利函数和一个公共类: `timeit.``timeit`(*stmt='pass'*, *setup='pass'*, *timer=<default timer>*, *number=1000000*, *globals=None*)使用给定语句、 *setup* 代码和 *timer* 函数创建一个 [`Timer`](#timeit.Timer "timeit.Timer") 实例,并执行 *number* 次其 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 方法。可选的 *globals* 参数指定用于执行代码的命名空间。 在 3.5 版更改: 添加可选参数 *globals* 。 `timeit.``repeat`(*stmt='pass'*, *setup='pass'*, *timer=<default timer>*, *repeat=5*, *number=1000000*, *globals=None*)使用给定语句、 *setup* 代码和 *timer* 函数创建一个 [`Timer`](#timeit.Timer "timeit.Timer") 实例,并使用给定的 *repeat* 计数和 *number* 执行运行其 [`repeat()`](#timeit.Timer.repeat "timeit.Timer.repeat") 方法。可选的 *globals* 参数指定用于执行代码的命名空间。 在 3.5 版更改: 添加可选参数 *globals* 。 在 3.7 版更改: *repeat* 的默认值由 3 更改为 5 。 `timeit.``default_timer`()默认的计时器,总是 [`time.perf_counter()`](time.xhtml#time.perf_counter "time.perf_counter") 。 在 3.3 版更改: [`time.perf_counter()`](time.xhtml#time.perf_counter "time.perf_counter") 现在是默认计时器。 *class* `timeit.``Timer`(*stmt='pass'*, *setup='pass'*, *timer=<timer function>*, *globals=None*)用于小代码片段的计数执行速度的类。 构造函数接受一个将计时的语句、一个用于设置的附加语句和一个定时器函数。两个语句都默认为 `'pass'` ;计时器函数与平台有关(请参阅模块文档字符串)。 *stmt* 和 *setup* 也可能包含多个以 `;` 或换行符分隔的语句,只要它们不包含多行字符串文字即可。该语句默认在 timeit 的命名空间内执行;可以通过将命名空间传递给 *globals* 来控制此行为。 要测量第一个语句的执行时间,请使用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 方法。 [`repeat()`](#timeit.Timer.repeat "timeit.Timer.repeat") 和 [`autorange()`](#timeit.Timer.autorange "timeit.Timer.autorange") 方法是方便的方法来调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 多次。 *setup* 的执行时间从总体计时执行中排除。 *stmt* 和 *setup* 参数也可以使用不带参数的可调用对象。这将在一个计时器函数中嵌入对它们的调用,然后由 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 执行。请注意,由于额外的函数调用,在这种情况下,计时开销会略大一些。 在 3.5 版更改: 添加可选参数 *globals* 。 `timeit`(*number=1000000*)执行 *number* 次主要语句。这将执行一次 setup 语句,然后返回执行主语句多次所需的时间,以秒为单位测量为浮点数。参数是通过循环的次数,默认为一百万。要使用的主语句、 setup 语句和 timer 函数将传递给构造函数。 注解 默认情况下, [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 暂时关闭 [garbage collection](../glossary.xhtml#term-garbage-collection) 。这种方法的优点在于它使独立时序更具可比性。缺点是GC可能是所测量功能性能的重要组成部分。如果是这样,可以在 *setup* 字符串中的第一个语句重新启用GC。例如: ``` timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit() ``` `autorange`(*callback=None*)自动决定调用多少次 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 。 这是一个便利函数,它反复调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") ,以便总时间 >= 0.2 秒,返回最终(循环次数,循环所用的时间)。它调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 的次数以序列 1, 2, 5, 10, 20, 50, ... 递增,直到所用的时间至少为0.2秒。 如果给出 *callback* 并且不是 `None` ,则在每次试验后将使用两个参数调用它: `callback(number, time_taken)` 。 3\.6 新版功能. `repeat`(*repeat=5*, *number=1000000*)调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 几次。 这是一个方便的函数,它反复调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") ,返回结果列表。第一个参数指定调用 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 的次数。第二个参数指定 [`timeit()`](#timeit.Timer.timeit "timeit.Timer.timeit") 的 *number* 参数。 注解 从结果向量计算并报告平均值和标准差这些是很诱人的。但是,这不是很有用。在典型情况下,最低值给出了机器运行给定代码段的速度的下限;结果向量中较高的值通常不是由Python的速度变化引起的,而是由于其他过程干扰你的计时准确性。所以结果的 [`min()`](functions.xhtml#min "min") 可能是你应该感兴趣的唯一数字。之后,你应该看看整个向量并应用常识而不是统计。 在 3.7 版更改: *repeat* 的默认值由 3 更改为 5 。 `print_exc`(*file=None*)帮助程序从计时代码中打印回溯。 典型使用: ``` t = Timer(...) # outside the try/except try: t.timeit(...) # or t.repeat(...) except Exception: t.print_exc() ``` 与标准回溯相比,优势在于将显示已编译模板中的源行。可选的 *file* 参数指向发送回溯的位置;它默认为 [`sys.stderr`](sys.xhtml#sys.stderr "sys.stderr") 。 ## 命令行界面 从命令行调用程序时,使用以下表单: ``` python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...] ``` 如果了解以下选项: `-n`` N``, ``--number``=N`执行 '语句' 多少次 `-r`` N``, ``--repeat``=N`重复计时器的次数(默认为5) `-s`` S``, ``--setup``=S`最初要执行一次的语句(默认为 `pass` ) `-p````, ``--process```测量进程时间,而不是 wallclock 时间,使用 [`time.process_time()`](time.xhtml#time.process_time "time.process_time") 而不是 [`time.perf_counter()`](time.xhtml#time.perf_counter "time.perf_counter") ,这是默认值 3\.3 新版功能. `-u````, ``--unit``=U`> 指定定时器输出的时间单位;可以选择 nsec,usec,msec或sec 3\.5 新版功能. `-v````, ``--verbose```打印原始计时结果;重复更多位数精度 `-h````, ``--help```打印一条简短的使用信息并退出 可以通过将每一行指定为单独的语句参数来给出多行语句;通过在引号中包含参数并使用前导空格可以缩进行。多个 [`-s`](#cmdoption-timeit-s) 选项的处理方式相似。 如果 [`-n`](#cmdoption-timeit-n) 未给出,则通过尝试10的连续幂次来计算合适数量的循环,直到总时间至少为 0.2 秒。 [`default_timer()`](#timeit.default_timer "timeit.default_timer") 测量可能受到在同一台机器上运行的其他程序的影响,因此在需要精确计时时最好的做法是重复几次计时并使用最佳时间。 [`-r`](#cmdoption-timeit-r) 选项对此有利;在大多数情况下,默认的 5 次重复可能就足够了。 你可以使用 [`time.process_time()`](time.xhtml#time.process_time "time.process_time") 来测量CPU时间。 注解 执行 pass 语句会产生一定的基线开销。这里的代码不会试图隐藏它,但你应该知道它。可以通过不带参数调用程序来测量基线开销,并且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`](#timeit.Timer "timeit.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()`](functions.xhtml#hasattr "hasattr") 与 [`try`](../reference/compound_stmts.xhtml#try)/[`except`](../reference/compound_stmts.xhtml#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`](#module-timeit "timeit: Measure the execution time of small code snippets.") 模块访问你定义的函数,你可以传递一个包含 import 语句的 *setup* 参数: ``` 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()`](functions.xhtml#globals "globals") 传递给 *globals* 参数,这将导致代码在当前的全局命名空间中执行。这比单独指定 import 更方便 ``` def f(x): return x**2 def g(x): return x**4 def h(x): return x**8 import timeit print(timeit.timeit('[func(42) for func in (f,g,h)]', globals=globals())) ``` ### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](trace.xhtml "trace --- Trace or track Python statement execution") | - [上一页](profile.xhtml "The Python Profilers") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python 标准库](index.xhtml) » - [调试和分析](debug.xhtml) » - $('.inline-search').show(0); | © [版权所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 软件基金会是一个非盈利组织。 [请捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [发现了问题](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 创建。