1. 程式人生 > 程式設計 >Python如何給你的程式做效能測試

Python如何給你的程式做效能測試

問題

你想測試你的程式執行所花費的時間並做效能測試。

解決方案

如果你只是簡單的想測試下你的程式整體花費的時間, 通常使用Unix時間函式就行了,比如:

bash % time python3 someprogram.py
real 0m13.937s
user 0m12.162s
sys 0m0.098s
bash %

如果你還需要一個程式各個細節的詳細報告,可以使用 cProfile 模組:

bash % python3 -m cProfile someprogram.py
     859647 function calls in 16.016 CPU seconds

  Ordered by: standard name

  ncalls tottime percall cumtime percall filename:lineno(function)
  263169  0.080  0.000  0.080  0.000 someprogram.py:16(frange)
   513  0.001  0.000  0.002  0.000 someprogram.py:30(generate_mandel)
  262656  0.194  0.000  15.295  0.000 someprogram.py:32(<genexpr>)
    1  0.036  0.036  16.077  16.077 someprogram.py:4(<module>)
  262144  15.021  0.000  15.021  0.000 someprogram.py:4(in_mandelbrot)
    1  0.000  0.000  0.000  0.000 os.py:746(urandom)
    1  0.000  0.000  0.000  0.000 png.py:1056(_readable)
    1  0.000  0.000  0.000  0.000 png.py:1073(Reader)
    1  0.227  0.227  0.438  0.438 png.py:163(<module>)
   512  0.010  0.000  0.010  0.000 png.py:200(group)
  ...
bash %

不過通常情況是介於這兩個極端之間。比如你已經知道程式碼執行時在少數幾個函式中花費了絕大部分時間。 對於這些函式的效能測試,可以使用一個簡單的裝飾器:

# timethis.py

import time
from functools import wraps

def timethis(func):
  @wraps(func)
  def wrapper(*args,**kwargs):
    start = time.perf_counter()
    r = func(*args,**kwargs)
    end = time.perf_counter()
    print('{}.{} : {}'.format(func.__module__,func.__name__,end - start))
    return r
  return wrapper

要使用這個裝飾器,只需要將其放置在你要進行效能測試的函式定義前即可,比如:

>>> @timethis
... def countdown(n):
...   while n > 0:
...       n -= 1
...
>>> countdown(10000000)
__main__.countdown : 0.803001880645752
>>>

要測試某個程式碼塊執行時間,你可以定義一個上下文管理器,例如:

from contextlib import contextmanager

@contextmanager
def timeblock(label):
  start = time.perf_counter()
  try:
    yield
  finally:
    end = time.perf_counter()
    print('{} : {}'.format(label,end - start))

下面是使用這個上下文管理器的例子:

>>> with timeblock('counting'):
...   n = 10000000
...   while n > 0:
...       n -= 1
...
counting : 1.5551159381866455
>>>

對於測試很小的程式碼片段執行效能,使用 timeit 模組會很方便,例如:

>>> from timeit import timeit
>>> timeit('math.sqrt(2)','import math')
0.1432319980012835
>>> timeit('sqrt(2)','from math import sqrt')
0.10836604500218527
>>>

timeit 會執行第一個引數中語句100萬次並計算執行時間。 第二個引數是執行測試之前配置環境。如果你想改變迴圈執行次數, 可以像下面這樣設定 number 引數的值:

>>> timeit('math.sqrt(2)','import math',number=10000000)
1.434852126003534
>>> timeit('sqrt(2)','from math import sqrt',number=10000000)
1.0270336690009572
>>>

討論

當執行效能測試的時候,需要注意的是你獲取的結果都是近似值。 time.perf_counter() 函式會在給定平臺上獲取最高精度的計時值。 不過,它仍然還是基於時鐘時間,很多因素會影響到它的精確度,比如機器負載。 如果你對於執行時間更感興趣,使用 time.process_time() 來代替它。例如:

from functools import wraps
def timethis(func):
  @wraps(func)
  def wrapper(*args,**kwargs):
    start = time.process_time()
    r = func(*args,**kwargs)
    end = time.process_time()
    print('{}.{} : {}'.format(func.__module__,end - start))
    return r
  return wrapper

最後,如果你想進行更深入的效能分析,那麼你需要詳細閱讀 time 、timeit 和其他相關模組的文件。 這樣你可以理解和平臺相關的差異以及一些其他陷阱。 還可以參考13.13小節中相關的一個建立計時器類的例子。

以上就是Python如何給你的程式做效能測試的詳細內容,更多關於Python做效能測試的資料請關注我們其它相關文章!