一、說明
我們簡單地分析性能,可以通過運行前后的datatime.datatime.now()相減來確定運行兩個時間中間的代碼花費了多少時間。
但這種做法只能記錄單次運行花費的時間、不能方便計算運行多次平均花費的時間,更不能深入分析整個程序各函數所花費的時間。
二、利用timeit分析語句/函數性能
示例代碼如下:
import timeit def test(): """Stupid test function""" for i in range(10000): # print(i) continue # 運行test函數10次,返回平均每次耗費的時間 # timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None) print("timeit directly:") print(timeit.timeit(stmt="test()", setup="from __main__ import test", number=10)) # stmt參數也可以是直接的一條語句,下同 # print(timeit.timeit(stmt="'-'.join(str(n) for n in range(100))", setup="from __main__ import test", number=10)) # 運行test函數10次,返回各次所耗費時間組成的列表 # timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None) print("\nrepeat directly:") print(timeit.repeat(stmt="test()", setup="from __main__ import test", number=10)) # 使用類的用處是對於同一條語句或函數,只寫一次,就可以周時用來timeit和repeat # class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>, globals=None) timeit_obj = timeit.Timer(stmt="test()", setup="from __main__ import test") # timeit.Timer.timeit(number=1000000) print("\ntimeit by class:") print(timeit_obj.timeit(number=10)) # timeit.Timer.repeat(repeat=5, number=1000000) print("\nrepeat by class:") print(timeit_obj.repeat(number=10))
運行結果如下:
三、使用profile分析整個程序性能
示例代碼如下:
import time import cProfile, pstats, profile def add(x, y): time.sleep(1) value = x + y return value def sub(x, y): time.sleep(1.5) value = x - y return value class TestProfile: def calc(self, x, y): time.sleep(1) add_result = add(x, y) sub_result = sub(x, y) print(f"{x} add {y} result is: {add_result}") print(f"{x} sub {y} result is: {sub_result}") if __name__ == '__main__': obj = TestProfile() # 要分析的函數。 # 原來調用該怎么寫就寫成相應的字符串形式就好了 be_analysed_function = "obj.calc(1,2)" # 給此次監測命個名,隨意起。 analysed_tag_name = "test_analysed" # 使用c語言版的profile進行分析,好處是自身占用資源更少,對函數的耗時定位更准確 cProfile.run(be_analysed_function, analysed_tag_name) # 使用python版的profile進行分析,格式都一樣的。 # profile.run(be_analysed_function, analysed_tag_name) # 對此次監測進行分析。 s = pstats.Stats(analysed_tag_name) # 移除文件目錄,減少打印輸出 # s.strip_dirs() # 排序。 # "time"表示按函數總耗時排序,python3.7后可用枚舉變量pstat.SortKey來取排序項 s.sort_stats("time") # 打印統計結果 # ncalls--函數被調用的次數 # tottime--此函數在所有調用中共耗費的時間秒數(不包括其調用的子函數耗費的時間)。分析耗時主要看這個。 # percall--此函數平均每次被調用耗時。分析耗時次要看這個 # cumtime--執行此函數及其調用子函數所占用的時間。 # percall--此函數平均每次調用每個子函數所用的時間。 s.print_stats() # print_stats的結果並不顯示誰調用的誰,比如是A調用的C還是B調用的C是不清楚的 # 要打印出函數的調用者,可使用print_callers() # 結果中右邊是被調用函數,左邊是調用該函數的函數 # s.print_callers()
運行結果如下圖:
參考:
https://docs.python.org/3/library/profile.html#module-cProfile