程式碼分析
首先,你應該能夠找到指令碼的瓶頸,並注意到沒有優化可以彌補資料結構中糟糕的選擇或演算法設計中的缺陷。其次,不要試圖在編碼過程中過早優化,而犧牲可讀性/設計/質量。Donald Knuth 就優化發表了以下宣告:
“我們應該忘記效率低,大約 97%的時間說:過早的優化是所有邪惡的根源。但我們不應該放棄我們在那個關鍵的 3%的機會”
要分析你的程式碼,你可以使用以下工具:cProfile
(或較慢的 profile
)來自標準庫 line_profiler
和 timeit
。他們每個人都有不同的目的。
cProfile
是一個確定性分析器:監視函式呼叫,函式返回和異常事件,併為這些事件之間的間隔(最多 0.001 秒)進行精確計時。庫文件([ https://docs.python.org/2/library/profile.html] [1 ]) 為我們提供了一個簡單的用例
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
或者,如果你希望包裝現有程式碼的一部分:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
這將建立如下表所示的輸出,你可以在其中快速檢視程式花費大部分時間的位置並確定要優化的功能。
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
模組 line_profiler
([ https://github.com/rkern/line_profiler] [1 ]) 對於對程式碼進行逐行分析非常有用。對於長指令碼來說,這顯然是不可控制的,但是針對的是片段。有關詳細資訊,請參閱文件。最簡單的入門方法是使用 kernprof 指令碼,如包頁面中所述,請注意你需要手動指定要分析的函式。
$ kernprof -l script_to_profile.py
kernprof 將建立一個 LineProfiler 例項,並將其插入到名稱為 profile 的 __builtins__
名稱空間中。它已被編寫為用作裝飾器,因此在你的指令碼中,你可以使用 @profile
來裝飾要分析的功能。
@profile
def slow_function(a, b, c):
...
kernprof 的預設行為是將結果放入二進位制檔案 script_to_profile.py.lprof
中。你可以告訴 kernprof 使用[-v / - view]選項立即在終端上檢視格式化結果。否則,你可以稍後檢視結果:
$ python -m line_profiler script_to_profile.py.lprof
最後,timeit
提供了一種從命令列和 python shell 測試一個襯裡或小表示式的簡單方法。該模組將回答諸如以下問題:在將列集轉換為列表時,更快地執行列表解析還是使用內建的 list()
。查詢 setup
關鍵字或 -s
選項以新增設定程式碼。
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
從一個終端
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop