在數據分析工作中,針對百萬,千萬級別的數據進行分析是常有的事情,
因此,分析代碼性能的重要性不容忽視,能夠有一個方便快速的測試函數性能的方法,
對於我們快速發現性能瓶頸,及時優化,提高項目的開發效率至關重要。
本文介紹如何通過Python裝飾器來實現性能計時工具,
幫助我們在不改變現有代碼的基礎上,隨時測試函數的執行時間。
1. 概要
用裝飾器來實現這樣計時的工具有以下一些好處:
首先,侵入性小,使用裝飾器可以非常方便地爲函數添加性能計時功能,則無需修改函數的內部代碼。
這使得代碼更加整潔,也更容易維護。
其次,複用性強,一旦創建了一個性能計時裝飾器,就可以將其應用於多個函數,而無需爲每個函數單獨編寫性能計時的代碼。
這樣不僅提高了代碼的效率,也降低了出錯的可能性。
最後,是靈活度高,裝飾器允許你根據需要定製性能計時的行爲,不僅可以打印到終端,也可以根據需求將性能測試結果寫入文件或者數據庫。
2. 實現計時機制
下面是我目前在用的一個計時裝飾器,開發過程中經常用它來看看可能存在性能問題的函數的執行時間。
from functools import wraps
from time import perf_counter
def timeit(loop: int = 1):
"""
函數執行失敗時,重試
:param loop: 循環執行次數
:return:
"""
# 校驗參數,參數值不正確時使用默認參數
if loop < 1:
loop = 1
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
sum_time: float = 0.0
for i in range(loop):
start_time: float = perf_counter()
ret = func(*args, **kwargs)
end_time: float = perf_counter()
sum_time += end_time - start_time
print(
f"函數({func.__name__})共執行{loop}次,平均執行時間 {(sum_time/loop):.3f} 秒"
)
return ret
return wrapper
return decorator
這個裝飾器只有一個參數(loop
),這個參數可以設置需要反覆執行幾次待測試的函數(func
)。
比如loop
設置100
,這個裝飾器會計算函數(func
)執行100
次的平均時間。
3. 使用示例
我們用一個模擬的耗時計算函數(compute
)來看看這個裝飾器的效果。
from decorators import timeit
import time
import random
@timeit(1)
def compute():
time.sleep(random.random() / 10)
return 100
if __name__ == "__main__":
result = compute()
print(f"{result = }")
從運行結果可以看出,這個timeit
裝飾器不影響函數的返回值,
不過,這裏只執行一次,執行時間存在一定的隨機性。
可以將上面代碼中的@timeit(1)
改成@timeit(100)
,再看看執行結果。
執行次數多了之後,平均執行時間開始逼近隨機數的中值0.05
。
一般性能測試時,都會設置loop
這個參數至少大於10
,而不會只執行一次。
4. 總結
總之,基於Python裝飾器實現的函數性能計時工具具有代碼簡潔、複用性強、靈活度高、便於性能分析、易於集成等諸多好處。
這些好處使得它成爲我們在進行代碼性能分析和優化時的有力工具。