標籤:form 今天 理解 變數 記憶體 timer round pytho print
之前用 JS 寫項目的時候,項目組用的組件模式,一直感覺很不錯。最近用 Python 做新項目,項目結構也延續了組件模式。一直沒有對函數調用的效能作瞭解,今天突發奇想測試了一下,寫了一些測試代碼
首先定義了幾個 class :
class A(object): def test(self): passclass B(object): def __init__(self): self.a = A() def test(self): passclass C(object): def __init__(self): self.b = B() def test(self): passclass D(object): def __init__(self): self.c = C() def test(self): pass
對比1:
直接調用執行個體對象身上的方法 和 使用變數緩衝該方法然後調用
n = 10000000import timeita = A()t_direct = timeit.Timer(‘a.test()‘, ‘from __main__ import a‘).timeit(n)print ‘direct call func : ‘, t_directcache = a.testt_cache = timeit.Timer(‘cache()‘, ‘from __main__ import cache‘).timeit(n)print ‘cache func call : ‘, t_cacheprint ‘ performance : ‘, (t_cache / t_direct)
嘗試多次後得出該情況下的時間結論:
direct call func : 1.14136314392cache func call : 0.745277881622 performance : 0.652971743123
緩衝方法之後再調用,效能大約能提升 35%
調用函數時,python 會臨時建立一個對象,比如直接調用函數 a.test() 時,python 會執行如下步驟:
1: temp = a.test
2: temp()
3: del temp
所以頻繁調用時,效能上是一個問題。記憶體上應該也是一個問題,感覺會更加頻繁的觸發 gc
對比2:
通過成員變數多層調用一個函數,和直接調用對象身上的函數的效能差
t0 = timeit.Timer(‘d.test()‘, ‘from __main__ import d‘).timeit(n)print ‘0 level: ‘, t0t1 = timeit.Timer(‘d.c.test()‘, ‘from __main__ import d‘).timeit(n)print ‘1 level: ‘, t1, ‘ : ‘, (t1 / t0) * 100t2 = timeit.Timer(‘d.c.b.test()‘, ‘from __main__ import d‘).timeit(n)print ‘2 level: ‘, t2, ‘ : ‘, (t2 / t1) * 100, ‘ ‘, (t2 / t0 * 100)t3 = timeit.Timer(‘d.c.b.a.test()‘, ‘from __main__ import d‘).timeit(n)print ‘3 level: ‘, t3, ‘ : ‘, (t3 / t2) * 100, ‘ ‘, (t3 / t0 * 100)
嘗試多次後得出該情況下的時間結論:
0 level: 1.26769399643
1 level: 1.50338602066 : 118.592185882
2 level: 1.74297595024 : 115.936687337 137.491851752
3 level: 1.87865877151 : 107.784549251 148.194972667
基本上,函數調用層次多一層,效能消耗會多 5% 到 15% 左右
這個暫時無法詳細的解答。手上也沒有 JS 的測試資料,不確定當時 js 些寫項目的時候,是否也存在這個效能問題。
之前碰到一些項目的結構是,寫的時候分成了多個檔案來寫,但是最後啟動並執行時候,會把這多個檔案中定義的 屬性、函數都彙總到一個 class 身上,成為一個巨無霸級的 class。一直不理解這麼做的意義是什麼,感覺很臃腫,現在看來 估計為了減少函數調用的層次,提高效能。
Python 函數調用效能記錄