1. 程式人生 > 其它 >(轉)Python timeit模組的使用實踐

(轉)Python timeit模組的使用實踐

原文:http://www.zhuchaoyouxi.com/article/359325.html

Python 中的 timeit 模組可以用來測試一段程式碼的執行耗時,如一個變數賦值語句的執行時間,一個函式的執行時間等。

timeit 模組是 Python 標準庫中的模組,無需安裝,直接匯入就可以使用。匯入時直接 import timeit ,可以使用timeit() 函式和 repeat() 函式,還有Timer 類。使用 from timeit import ... 時,只能匯入 Timer 類(有全域性變數 __all__ 限制)。

timeit 模組的原始碼總共只有 300 多行,主要就是實現上面的兩個函式和一個類,可以自己看一下。

接下來就開始使用 timeit 模組來測試程式碼執行時間,我使用 timeit 模組來對比 Python 列表從頭部新增資料和從尾部新增資料的執行時間(測試什麼根據需求來定)。

一、使用 timeit() 函式測試執行時間

1. 準備測試函式

先寫兩個函式,一個函式是從列表頭部新增資料,另一個函式是從列表尾部新增資料。

# coding=utf-8
def insert_time_test():
  insert_list = list()
  for i in range(10):
    insert_list.insert(0, i)
def append_time_test():
  append_list = list()
  for i in range(10):
    append_list.append(i)
if __name__ == '__main__':
  import timeit

2.timeit(stmt="pass", setup="pass", timer=default_timer, number=default_number) 函式介紹

timeit() 函式有四個引數,每個引數都是關鍵字引數,都有預設值。

stmt:傳入需要測試時間的程式碼,可以直接傳入程式碼表達式或單個變數,也可以傳入函式。傳入函式時要在函式名後面加上小括號,讓函式執行,如 stmt = ‘func()' 。

setup:傳入 stmt 的執行環境,如 stmt 中使用到的引數、變數,要匯入的模組等,如 setup = ‘from __main__ import func'。可以寫一行語句,也可以寫多行語句,寫多行語句時用分號隔開。

如果 stmt 和引數 setup 引數不傳值,那麼就失去了測試的意義,所以這兩個引數是必要的。

timer: timer 引數是當前作業系統的基本時間單位,預設會根據當前執行環境的作業系統自動獲取(原始碼中已經定義),保持預設即可。

number:要測試的程式碼的執行次數,預設1000000(一百萬)次,對於耗時的程式碼,執行太多次會花很多時間,可以自己修改執行次數。

3. 測試函式的執行時間

現在使用timeit() 來測試上面兩個函式的執行時間。

  insert_time_timeit = timeit.timeit(stmt='insert_time_test()', 
                    setup='from __main__ import insert_time_test')
  print('insert_time_timeit: ', insert_time_timeit)
  append_time_timeit = timeit.timeit(stmt='append_time_test()', 
                    setup='from __main__ import append_time_test')
  print('append_time_timeit: ', append_time_timeit)

執行結果:

('insert_time_timeit: ', 2.9112871)
('append_time_timeit: ', 1.8884124999999998)

可以看到,在列表頭部新增資料的時間比在列表尾部新增資料的時間長。

4. 測試程式碼(表示式)的執行時間

繼續使用timeit() 測試上面程式碼的執行時間,只是這次是直接將程式碼傳入到引數中,而不是傳入函式。

  insert_time_timeit = timeit.timeit(stmt='list(insert_list.insert(0, i) for i in init_list)',
                    setup='insert_list=list();init_list=range(10)',
                    number=100000)
  print('insert_time_timeit: ', insert_time_timeit)
  append_time_timeit = timeit.timeit(stmt='list(append_list.append(i) for i in init_list)',
                    setup='append_list=list();init_list=range(10)',
                    number=100000)
  print('append_time_timeit: ', append_time_timeit)

由於時間很長,程式碼中特意將 number 從一百萬次改成了十萬次。執行結果如下:

('insert_time_timeit: ', 330.46189400000003)
('append_time_timeit: ', 0.21436310000001413)

相對來說,對於相同的操作,使用函式的執行時間遠小於直接傳入程式碼表達式的時間,頭部插入資料的尤其明顯。

二、使用 repeat() 函式測試執行時間

1.repeat(stmt="pass", setup="pass", timer=default_timer, repeat=default_repeat, number=default_number) 函式介紹

repeat() 函式有五個引數,每個引數都是關鍵字引數,都有預設值。相比timeit() 函式而言,timeit() 函式有的引數 repeat() 函式都有,此外,repeat() 函式多了一個repeat 引數。

repeat:表示測試要重複幾次,可以理解為將相同引數的 timeit() 函式重複執行。最終的結果構成一個列表返回,repeat 預設為3次。

2. 測試函式的執行時間

現在使用repeat() 來測試上面兩個函式的執行時間。

 insert_time_repeat = timeit.repeat(stmt='insert_time_test()',
                    setup='from __main__ import insert_time_test')
  print('insert_time_repeat: ', insert_time_repeat)
  append_time_repeat = timeit.repeat(stmt='append_time_test()',
                    setup='from __main__ import append_time_test')

  print('append_time_repeat: ', append_time_repeat)

執行結果如下:

('insert_time_repeat: ', [2.7707739, 2.908885, 2.7164823999999994])
('append_time_repeat: ', [1.7458063, 1.777368000000001, 1.8675014999999995])

3. 測試程式碼(表示式)的執行時間

繼續使用repeat() 測試上面程式碼的執行時間,直接傳入程式碼,上面將 number 改成十萬次後,時間還是很長(300多秒),所以繼續減小 number ,改成一萬次。

  insert_time_repeat = timeit.repeat(stmt='list(insert_list.insert(0, i) for i in init_list)',
                    setup='insert_list=list();init_list=range(10)',
                    repeat=5,
                    number=10000)
  print('insert_time_repeat: ', insert_time_repeat)
  append_time_repeat = timeit.repeat(stmt='list(append_list.append(i) for i in init_list)',
                    setup='append_list=list();init_list=range(10)',
                    repeat=5,
                    number=10000)
  print('append_time_repeat: ', append_time_repeat)

執行結果如下:

('insert_time_repeat: ', [2.591015, 2.5814996999999997, 2.5547322, 2.6153070000000005, 2.5496864000000006])
('append_time_repeat: ', [0.0181692999999985, 0.01746889999999901, 0.018901899999999472, 0.018737400000000903, 0.018211900000000725])

三、使用 Timer類測試執行時間

1.Timer 類介紹

上面使用了 timeit() 函式和 repeat() 函式,其實在 timeit 模組中,這兩個函式都是對 Timer 類做了進一步的封裝,實際呼叫的還是 Timer 類中的方法。

在 Timer 類中,實現了兩個方法,timeit() 方法和 repeat() 方法,上面兩個函式呼叫的就是這兩個方法。

在使用 from timeit import ... 時,只能匯入 Timer 類,所以可以直接使用 Timer 類來測試,可以自己去呼叫方法,使用起來更靈活。

2. 測試列表頭部新增

先例項化一個 Timer 類的物件,例項化時傳入 stmt 和 setup 引數(引數的含義與上面一致),timer 引數保持預設,然後通過例項物件呼叫對應的 timeit() 方法或 repeat() 方法,在 timeit() 方法中傳入 number,在repeat() 方法中傳入 number 和repeat 。

使用timeit() 方法和repeat() 方法測試從頭部新增資料的執行時間。

 timer_insert = timeit.Timer(stmt='insert_time_test()', setup='from __main__ import insert_time_test')
  insert_time_timeit = timer_insert.timeit(number=1000000)
  print('insert_time_timeit: ', insert_time_timeit)
  insert_time_repeat = timer_insert.repeat(number=1000000)
  print('insert_time_repeat: ', insert_time_repeat)

執行結果如下:

('insert_time_timeit: ', 2.7732486)
('insert_time_repeat: ', [2.7367806999999997, 2.707402600000001, 2.7288245999999994])

3. 測試列表尾部新增

使用timeit() 方法和repeat() 方法測試從尾部新增資料的執行時間。

  timer_append = timeit.Timer(stmt='append_time_test()', setup='from __main__ import append_time_test')
  append_time_timeit = timer_append.timeit(number=1000000)
  print('append_time_timeit: ', append_time_timeit)
  append_time_repeat = timer_append.repeat(number=1000000)
  print('append_time_repeat: ', append_time_repeat)

執行結果如下:

('append_time_timeit: ', 1.9966106000000001)
('append_time_repeat: ', [1.9523343999999998, 1.8373857999999998, 1.8695377000000004])

timeit 模組是一個比較簡單的模組,大概用法就這些了。

技術連結