Python精確統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的多種方法
一、為什么需要統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間
- 識(shí)別性能瓶頸,優(yōu)化關(guān)鍵代碼路徑
- 對(duì)比不同算法或?qū)崿F(xiàn)的性能差異,量化優(yōu)化效果
- 監(jiān)控生產(chǎn)環(huán)境中關(guān)鍵功能的性能表現(xiàn)
- 建立性能基準(zhǔn),評(píng)估代碼改進(jìn)效果
- 診斷偶發(fā)的性能下降問(wèn)題
二、Python中的時(shí)間統(tǒng)計(jì)方法
使用 time 模塊
import time
start_time = time.time() # 記錄開(kāi)始時(shí)間
your_function() # 執(zhí)行目標(biāo)函數(shù)
end_time = time.time() # 記錄結(jié)束時(shí)間
execution_time = end_time - start_time
print(f"函數(shù)執(zhí)行時(shí)間: {execution_time:.6f}秒")
特點(diǎn):
- 簡(jiǎn)單直接
- 精度約為毫秒級(jí)
- 受系統(tǒng)時(shí)間調(diào)整影響
使用 time.perf_counter()
import time
start = time.perf_counter() # 高精度計(jì)時(shí)器
your_function()
end = time.perf_counter()
print(f"函數(shù)執(zhí)行時(shí)間: {end - start:.6f}秒")
特點(diǎn):
- 精度可達(dá)納秒級(jí)
- 不受系統(tǒng)時(shí)間調(diào)整影響
- 適合測(cè)量短時(shí)間間隔
注意
Windows 和 Linux 的底層計(jì)時(shí)機(jī)制不同,time.perf_counter()在不同操作系統(tǒng)上的精度可能略有差異。
使用 timeit 模塊
import timeit
# 測(cè)量單次執(zhí)行
time_taken = timeit.timeit('your_function()',
setup='from __main__ import your_function',
number=1)
print(f"執(zhí)行時(shí)間: {time_taken:.6f}秒")
# 測(cè)量多次執(zhí)行求平均
repeat = 1000
total_time = timeit.timeit('your_function()',
setup='from __main__ import your_function',
number=repeat)
print(f"平均執(zhí)行時(shí)間: {total_time/repeat:.6f}秒")
特點(diǎn):
- 自動(dòng)禁用垃圾回收以獲得更穩(wěn)定結(jié)果
- 適合測(cè)量小代碼段的執(zhí)行時(shí)間
- 可以方便地重復(fù)多次測(cè)量
使用裝飾器(推薦的解決方案)
import time
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"{func.__name__} 執(zhí)行時(shí)間: {end_time - start_time:.6f}秒")
return result
return wrapper
@timer
def example_function(n):
return sum(i*i for i in range(n))
example_function(1000000)
特點(diǎn):
- 代碼復(fù)用性高
- 非侵入式測(cè)量
- 可以輕松添加或移除計(jì)時(shí)功能
使用上下文管理器
from contextlib import contextmanager
import time
@contextmanager
def timer_context(name):
start = time.perf_counter()
yield
end = time.perf_counter()
print(f"{name} 執(zhí)行時(shí)間: {end - start:.6f}秒")
with timer_context("復(fù)雜計(jì)算"):
# 在這里執(zhí)行需要計(jì)時(shí)的代碼
result = sum(i*i for i in range(1000000))
特點(diǎn):
- 適合測(cè)量代碼塊的執(zhí)行時(shí)間
- 不需要封裝函數(shù)
- 可以嵌套使用
三、高級(jí)用法
對(duì)于更復(fù)雜的性能分析,可以使用 cProfile 模塊:
import cProfile
def your_function():
# 函數(shù)實(shí)現(xiàn)
pass
# 運(yùn)行性能分析
profiler = cProfile.Profile()
profiler.enable()
your_function()
profiler.disable()
profiler.print_stats(sort='time')
四、異步函數(shù)計(jì)時(shí)
異步代碼(async/await)的計(jì)時(shí)需要特殊處理,可以使用 asyncio 模塊提供的方法。
使用 asyncio 專用計(jì)時(shí)器
import asyncio
async def task():
start = asyncio.get_event_loop().time() # 事件循環(huán)內(nèi)部時(shí)鐘
await asyncio.sleep(1)
end = asyncio.get_event_loop().time()
print(f"耗時(shí): {end - start:.2f}秒") # 準(zhǔn)確記錄協(xié)程生命周期
asyncio.run(task())
隔離CPU耗時(shí)(適用于混合計(jì)算/IO場(chǎng)景)
async def pure_cpu_work():
start = time.perf_counter() # 僅測(cè)量CPU計(jì)算部分
result = sum(i*i for i in range(10**6))
end = time.perf_counter()
print(f"CPU計(jì)算耗時(shí): {end - start:.2f}秒")
return result
async def main():
await pure_cpu_work() # 只統(tǒng)計(jì)計(jì)算時(shí)間
await asyncio.sleep(1) # IO等待單獨(dú)處理
asyncio.run(main())
使用 asyncio.run() 包裝(Python 3.7+)
async def async_task():
await asyncio.sleep(1)
start = time.perf_counter()
asyncio.run(async_task()) # 包含事件循環(huán)啟動(dòng)/關(guān)閉時(shí)間
end = time.perf_counter()
print(f"總耗時(shí): {end - start:.2f}秒")
五、應(yīng)用建議
精度選擇
- 對(duì)于長(zhǎng)時(shí)間運(yùn)行的任務(wù)(>1秒),使用
time.time()足夠 - 對(duì)于短時(shí)間測(cè)量,使用
time.perf_counter()
多次測(cè)量
- 對(duì)于快速函數(shù),執(zhí)行多次求平均值
- 注意第一次執(zhí)行可能因緩存等因素較慢
環(huán)境控制
- 關(guān)閉其他占用CPU的程序
- 在相同環(huán)境下進(jìn)行比較測(cè)試
結(jié)果分析
- 關(guān)注相對(duì)差異而非絕對(duì)數(shù)值
- 考慮標(biāo)準(zhǔn)差而不僅是平均值
相對(duì)差異 vs 絕對(duì)數(shù)值
相對(duì)差異 = (新值 - 舊值)/舊值 × 100%
絕對(duì)數(shù)值 = 直接測(cè)量結(jié)果(如 0.25秒)
絕對(duì)差異0.05秒看似很小,但相對(duì)10%的提升可能是顯著的
不同機(jī)器/環(huán)境下絕對(duì)數(shù)值會(huì)變化,但相對(duì)差異通常保持穩(wěn)定
幫助判斷優(yōu)化有效性(如5%以下差異可能是測(cè)量誤差)
平均值 vs 標(biāo)準(zhǔn)差
平均值:所有測(cè)量結(jié)果的平均數(shù)
標(biāo)準(zhǔn)差(σ):數(shù)據(jù)離散程度的度量
高標(biāo)準(zhǔn)差可能暗示:
存在資源競(jìng)爭(zhēng)(如GC、線程切換)
特殊輸入導(dǎo)致性能波動(dòng)
測(cè)量環(huán)境不穩(wěn)定
示例:
# 兩組測(cè)量結(jié)果(單位:秒) 組A = [0.48, 0.49, 0.50, 0.51, 0.52] # 平均值0.50,σ≈0.015 組B = [0.35, 0.45, 0.50, 0.55, 0.65] # 平均值0.50,σ≈0.118 # 雖然平均值相同,但: # - 組A性能穩(wěn)定 # - 組B存在偶發(fā)的嚴(yán)重性能下降
在需要穩(wěn)定性的場(chǎng)景(如實(shí)時(shí)系統(tǒng)),低標(biāo)準(zhǔn)差比低平均值更重要。
六、常見(jiàn)誤區(qū)
- 只測(cè)量一次:?jiǎn)未螠y(cè)量可能受系統(tǒng)波動(dòng)影響
- 忽略預(yù)熱效應(yīng):第一次執(zhí)行通常較慢
- 測(cè)量包含打印時(shí)間:I/O操作會(huì)顯著影響結(jié)果
- 在開(kāi)發(fā)環(huán)境評(píng)估生產(chǎn)性能:環(huán)境差異可能導(dǎo)致結(jié)果不準(zhǔn)確
七、總結(jié)
Python 提供了多種統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的方法,從簡(jiǎn)單的 time.time() 到專業(yè)的 cProfile 工具。選擇合適的方法取決于具體需求:
- 快速檢查:使用
time.time()或裝飾器 - 精確測(cè)量:使用
time.perf_counter() - 重復(fù)測(cè)試:使用
timeit - 全面分析:使用
cProfile
通過(guò)合理使用這些工具,可以有效地識(shí)別和解決性能問(wèn)題,提升代碼效率。
以上就是Python統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的多種方法的詳細(xì)內(nèi)容,更多關(guān)于Python統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
pytorch動(dòng)態(tài)神經(jīng)網(wǎng)絡(luò)(擬合)實(shí)現(xiàn)
這篇文章主要介紹了pytorch動(dòng)態(tài)神經(jīng)網(wǎng)絡(luò)(擬合)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Python并發(fā)concurrent.futures和asyncio實(shí)例
這篇文章主要介紹了Python并發(fā)concurrent.futures和asyncio實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05
Python實(shí)現(xiàn)合并excel表格的方法分析
這篇文章主要介紹了Python實(shí)現(xiàn)合并excel表格的方法,結(jié)合實(shí)例形式分析了Python合并Excel表格的原理、實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2019-04-04

