Python裝飾器實戰:打造高效性能計時工具

在數據分析工作中,針對百萬,千萬級別的數據進行分析是常有的事情,
因此,分析代碼性能的重要性不容忽視,能夠有一個方便快速的測試函數性能的方法,
對於我們快速發現性能瓶頸,及時優化,提高項目的開發效率至關重要。

本文介紹如何通過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 = }")

image.png
從運行結果可以看出,這個timeit裝飾器不影響函數的返回值,
不過,這裏只執行一次,執行時間存在一定的隨機性。

可以將上面代碼中的@timeit(1)改成@timeit(100),再看看執行結果。
image.png
執行次數多了之後,平均執行時間開始逼近隨機數的中值0.05
一般性能測試時,都會設置loop這個參數至少大於10,而不會只執行一次。

4. 總結

總之,基於Python裝飾器實現的函數性能計時工具具有代碼簡潔、複用性強、靈活度高、便於性能分析、易於集成等諸多好處。
這些好處使得它成爲我們在進行代碼性能分析和優化時的有力工具。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章