摘要:本篇博客簡單講解如何給Python程序做profile。profie很有用的,它可以分解程序各個部分花費了多少時間。
1 line_profiler
在linux下我用time這個命令可以查看程序運行的總時間,user mode時間和kernel mode時間。但是如果想更進一步,查看程序內部哪一行命令花費多少時間,或者查找程序的瓶頸部分,就得用 line_profiler 這個包了。這對於優化程序很有幫助。
1.1 安裝
官方安裝方法:
pip install line_profiler
但是我用這個方法安裝失敗了。。。我是Anaconda環境,於是使用conda安裝,成功了:
conda install line_profiler
2 使用
分爲三個步驟:
- import line_profiler
- 給函數加上 @profile 這個裝飾器
- 在命令行裏面輸入 kernprof -v -l code.py
這裏code.py 是要做profile的程序
3 Talk is cheap, show me the code.
代碼:
import line_profiler
// ...
@profile
def findSubstring(self, s: str, words: List[str]) -> List[int]:
''' s -- O(N)
words -- O(M)
'''
from collections import defaultdict
if len(words) == 0 or len(s) == 0:
return []
answer = []
length = len(words[0])
s_pro = Solution.preprocess_s(s, length)
word_num = len(words)
word_dict = defaultdict(int)
for w in words:
word_dict[w] += 1
for i in range(0, len(s) - int(length*word_num) + 1):
words_tmp = Solution.get_words(s_pro, i, length, word_num)
if Solution.match_words(words_tmp, word_dict):
answer.append(i)
return answer
輸出:
Line # Hits Time Per Hit % Time Line Contents
==============================================================
149 @profile
150 def findSubstring(self, s: str, words: List[str]) -> List[int]:
151 ''' s -- O(N)
152 words -- O(M)
153 '''
154 1 11.0 11.0 0.0 from collections import defaultdict
155
156 1 1.0 1.0 0.0 if len(words) == 0 or len(s) == 0:
157 return []
158
159 1 0.0 0.0 0.0 answer = []
160 1 1.0 1.0 0.0 length = len(words[0])
161 1 4376.0 4376.0 0.2 s_pro = Solution.preprocess_s(s, length)
162 1 0.0 0.0 0.0 word_num = len(words)
163 1 2.0 2.0 0.0 word_dict = defaultdict(int)
164 201 77.0 0.4 0.0 for w in words:
165 200 96.0 0.5 0.0 word_dict[w] += 1
166 9602 4482.0 0.5 0.2 for i in range(0, len(s) - int(length*word_num) + 1):
167 9601 1079034.0 112.4 52.4 words_tmp = Solution.get_words(s_pro, i, length, word_num)
168 9601 972198.0 101.3 47.2 if Solution.match_words(words_tmp, word_dict):
169 answer.append(i)
170 1 0.0 0.0 0.0 return answer
3.1 分析
屬性 | 解釋 |
---|---|
line # | 行數 |
Hits | 這一行運行了多少次 |
Time | 在這一行上總共花費了多少時間 |
Per Hit | Time除以Hits |
% Time | 時間佔比 |
Line Contents | 這一行的代碼內容 |
可以看出,代碼第167行時間佔比是52.4%,第168行時間佔比47.2%。
4 討論
- 使用line_profiler會使程序運行變慢,時間大約翻倍。但是沒關係,line_profiler的的核心目的是找到程序的瓶頸部分,也就是時間佔比 %Time。如果每一行都變慢一樣的比例的話,不影響時間佔比。
- line_profiler不支持多進程,如果程序中使用了 joblib 或者 subprocess 的話,就不能用 line_profiler。
- line_profiler這個包是一個叫做Robert Kern的大牛寫的,所以命令叫做kernprof。
- cProfile 也可以做profile。我不常使用這個包,因爲我不喜歡這個包的輸出結果。line_profiler可以輸出每行的時間,這個我喜歡。
- 上述都是對時間做profile。對內存做profile呢?使用這個包:memory-profiler