timeit庫文檔:https://docs.python.org/zh-cn/3/library/timeit.html
timeit 是一個用來測量小代碼片段執行時間的工具庫,有命令行和函數調用兩種方法可供使用。
可以直接查看文檔最後的示例部分快速了解其用法。
注意:
需要注意的是,在命令行,傳給timeit 的 stmt 參數
(即要運行的測試代碼)都要是字符串格式的,而不是函數引用或Python語句。在函數中,除了字符串,可以傳入一個可調用對象。
命令行方式:
如果是在windows下使用命令行執行語句,切記最外層需要使用雙引號
,否則會報錯。
$ 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
函數調用:
>>> 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
在函數調用時,可以傳入可調用對象:
>>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000)
0.19665591977536678
但是請注意,timeit ()只有在使用命令行界面時才會自動確定重復次數。
模塊包含3個常用方法和一個Timer類:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
使用給定的stmt、setup代碼和timer函數創建一個 Timer 實例,並根據number運行它的 timeit ()方法。可選的 globals 參數指定在其中執行代碼的命名空間。
timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None)
使用給定的stmt和setup代碼和timer函數創建一個 Timer 實例,並使用給定的repeat計數和number執行運行它的 repeat ()方法(默認執行5 * 1000000次)。可選的 globals 參數指定在其中執行代碼的命名空間。
timeit.default_timer()
默認的計時器 time.perf_counter()
.
*class* timeit.Timer(stmt='pass', setup='pass', timer=<timer function>, globals=None)
用於計時小代碼端執行速度的類。該類包括timeit(), autorange(), repeat()和print_exec()
四個方法。
構造函數接受一條要計時的語句stmt、一條用於設置的附加語句setup和一個計時器函數。這兩個語句都默認為“ pass”; 計時器函數依賴於平台。Stmt 和 setup 還可以包含由; 或換行分隔的多個語句,只要它們不包含多行字符串文字。默認情況下,語句將在其名稱空間內執行; 可以通過將名稱空間傳遞給globals變量來控制此行為。
若要度量第一個語句stmt的執行時間,請使用 timeit ()方法。Repeat ()和 autOrange ()方法是方便多次調用 timeit ()的方法。setup語句的執行時間被排除在整個計時執行運行之外。
Stmt 和 setup 參數還可以接受不帶參數的可調用對象(callable)。這將把對它們的調用嵌入到一個計時器函數中,然後由 timeit ()執行。注意,在這種情況下,由於額外的函數調用,計時開銷有點大。
timeit(number=1000000)
:
主語句的執行時間。這會執行 setup 語句一次,然後返回執行主語句若干次所需的時間,以秒為單位作為浮點數進行計算。參數是通過循環的次數,默認為100萬次。主語句、 setup 語句和要使用的 timer 函數被傳遞給構造函數。
注意:在使用timeit()函數測試時,默認會臨時關閉Python的垃圾回收功能。這種方法的優點是它使獨立計時更具可比性。缺點是 GC 可能是被測量函數性能的重要組成部分。如果是這樣,GC 可以作為設置字符串中的第一條語句重新啟用。 timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
在創建Timer對象時的stmt中設置gc.enable()
。
autorange(callback=None)
:
自動確定調用 timeit ()的次數。
這是一個便捷函數,用來反復調用 timeit () ,使總時間 > = 0.2秒,返回最終結果(循環次數和循環花費的時間)。它使用序列1、2、5、10.20、50中的遞增數字調用 timeit () ,直到所花費的時間至少為0.2秒。
如果回調callback是給定的,並且不是 None,那麼在每次試驗之後將使用兩個參數調用它: callback (number,time_taken)
。
repeat(repeat=5, number=1000000)
:
調用計時器repeat次。
這是一個便捷函數,它重復調用 timeit () ,返回一個結果列表。第一個參數repeat指定調用 timeit ()的次數。第二個參數指定 timeit ()的 number 參數。
注意:從結果向量計算平均值和標准差並報告這些結果是很有誘惑力的。然而,這並不是很有用。在一個典型的例子中,最低值給出了您的計算機運行給定代碼片段的速度的下限; 結果向量中較高的值通常不是由 Python 速度的變化引起的,而是由於其他進程干擾了計時的准確性。因此,結果的 min ()可能是您應該感興趣的唯一數字。之後,您應該用常識看待整個向量而不是從統計的角度看待整個結果。
print_exc(file=None)
:
從計時代碼打印回溯的幫助程序。
t = Timer(...) # outside the try/except
try:
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 timer執行statement的次數
-r 重復執行timer的次數,默認為5
-u 指定timer輸出的時間格式,可以指定為:nsec、usec、msec、sec
-s setup 語句,默認為pass
-p 使用time.process_time()而不是默認的time.perf_counter()來度量進程時間,而不是牆鐘時間
-v 詳細信息,打印原始的計時結果
-h 幫助信息
一個多行的statement可以通過使用 ; 分給為多個語句,帶縮進的行可以使用引號括起一個參數並使用前導空格。-s選項的多行語法是類似的。
$ 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
使用-s 指定的setup語句只在開始時執行一次。
在輸出中有三個字段:
以上語句使用函數和Timer類的代碼如下:
>>> 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
>>> 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]
當statement語句中包含多行語句時,在命令行和Python代碼中可以如下執行:
$ 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
當要對我們定義的函數進行時間測量時,可以通過setup參數傳遞腳本中需要的 import 語句(即使是在當前腳本下也要import:from __main__ import func
),stmt 參數傳遞方法調用字符串化後的表達式:
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()
函數。這將導致代碼在當前全局命名空間內執行。這可能比單獨指定進口更方便:
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()))
In [2]: def test():
...: a = 0
...: for _ in range(1000):
...: a += _
...:
In [3]: timeit.timeit('test()', globals=globals())
Out[3]: 35.442787599982694
In [4]: timeit.timeit('test()', number=1, globals=globals())
Out[4]: 3.50000336766243e-05
In [5]: timeit.timeit('test()', number=10, globals=globals())
Out[5]: 0.00033359997905790806
In [6]: timeit.timeit('test()', number=100, globals=globals())
Out[6]: 0.0032857999904081225
In [7]: timeit.timeit('test()', number=1000, globals=globals())
Out[7]: 0.03538430004846305
>python -m timeit "a=0" "for _ in range(1000):" " a+=_"
10000 loops, best of 5: 32.4 usec per loop
# 以秒為單位
>python -m timeit -u sec "a=0" "for _ in range(1000):" " a+=_"
10000 loops, best of 5: 3.24e-05 sec per loop