項目情景描述:
在restful架構風格的項目交付測試的過程中,某接口出現 請求超時導致的http 502 Bad Gateway,於是開始排查具體是接口函數中的哪行代碼或函數 響應時間過長導致的502錯誤。
剛開始的解決方法:
土鱉式的導入 time模塊進行時間計算,從而查出具體響應時間過長的位置
如下:
1 import time import time 2 from flask import Flask 3 app = Flask(__name__) 4 5 app.route('/line_test') 6 def line_test(): 7 #土鱉方法 8 first_time=time() 9 for item in range(5): 10 time.sleep(1) 11 #土鱉方法 12 print time()-first_time 13 for item in xrange(5): 14 time.sleep(0.5) 15 #土鱉方法 16 print time()-first_time
方法缺點:需要大量時間編寫 關於 time()的代碼,最后還要刪除這些代碼,浪費時間
現在的解決方法:
使用python的 line_profiler 模塊,此模塊是用來測試 函數 每行代碼的響應時間等情況。
具體思路:將 line_profiler相關函數封裝在裝飾器 中 進行使用,這樣 在接口請求時,則會執行此裝飾器並打印出結果。
windows安裝方法:https://www.lfd.uci.edu/~gohlke/pythonlibs/#line_profiler
代碼如下:
1 #coding:utf8 2 from flask import Flask, jsonify 3 import time 4 from functools import wraps 5 from line_profiler import LineProfiler 6 7 #查詢接口中每行代碼執行的時間 8 def func_line_time(f): 9 @wraps(f) 10 def decorator(*args, **kwargs): 11 func_return = f(*args, **kwargs) 12 lp = LineProfiler() 13 lp_wrap = lp(f) 14 lp_wrap(*args, **kwargs)
15 lp.print_stats()
16 return func_return
17 return decorator
18
19
20 app = Flask(__name__)
21
22 @app.route('/line_test')
23 @func_line_time
24 def line_test():
25 for item in range(5):
26 time.sleep(1)
27 for item in xrange(5):
28 time.sleep(0.5)
29 return jsonify({'code':200})
30
31 if __name__=='__main__':
32 app.run()
當瀏覽器請求接口時得到的結果如下:
* Running on http://127.0.0.1:5000/ Timer unit: 1e-06 s Total time: 7.50827 s File: /home/rgc/baidu_eye/carrier/test/flask_line_profiler_test.py Function: line_test at line 22 Line # Hits Time Per Hit % Time Line Contents ============================================================== 22 @app.route('/line_test') 23 @func_line_time 24 def line_test(): 25 6 33.0 5.5 0.0 for item in range(5): 26 5 5005225.0 1001045.0 66.7 time.sleep(1) 27 6 31.0 5.2 0.0 for item in xrange(5): 28 5 2502696.0 500539.2 33.3 time.sleep(0.5) 29 1 282.0 282.0 0.0 return jsonify({'code':200}) 127.0.0.1 - - [05/Mar/2018 15:58:21] "GET /line_test HTTP/1.1" 200 -
返回結果中 具體 含義:
Total Time:測試代碼的總運行時間
Line:代碼行號
Hits:表示每行代碼運行的次數
Time:每行代碼運行的總時間
Per Hits:每行代碼運行一次的時間
% Time:每行代碼運行時間的百分比
從 中便可看到 具體 26行代碼執行時間最長。
方法優點:只需要添加一個裝飾器,再接口函數前引用即可,刪除也容易,且 裝飾器可以重復使用,節省大量時間。
其他關於line_profiler的使用方法:
在腳本中使用此方法:
1 #coding:utf8 2 import cgi 3 import time 4 from line_profiler import LineProfiler 5 6 def test2(): 7 print 'hello!test2()' 8 9 def test1(): 10 html='''<script>alert("you are a good boy!&I like you")</scrpit>''' 11 test2() 12 escape_html=cgi.escape(html) 13 for item in range(5): 14 time.sleep(1) 15 print escape_html 16
17 if __name__=='__main__': 18 lp=LineProfiler() 19 #同時顯示函數每行所用時間和調用函數每行所用時間,加入add_function() 20 lp.add_function(test2) 21 lp_wrap=lp(test1)
#如果被測函數有入參,下面一行為 lp_wrap(被測函數入參) 22 lp_wrap() 23 lp.print_stats()
直接運行顯示結果:
* Running on http://127.0.0.1:5000/ Timer unit: 1e-06 s Total time: 7.50827 s File: /home/rgc/baidu_eye/carrier/test/flask_line_profiler_test.py Function: line_test at line 22 Line # Hits Time Per Hit % Time Line Contents ============================================================== 22 @app.route('/line_test') 23 @func_line_time 24 def line_test(): 25 6 33.0 5.5 0.0 for item in range(5): 26 5 5005225.0 1001045.0 66.7 time.sleep(1) 27 6 31.0 5.2 0.0 for item in xrange(5): 28 5 2502696.0 500539.2 33.3 time.sleep(0.5) 29 1 282.0 282.0 0.0 return jsonify({'code':200}) 127.0.0.1 - - [05/Mar/2018 15:58:21] "GET /line_test HTTP/1.1" 200 -
相對於另一種使用方法:
1.在需要測試的函數前添加裝飾器 @profile
2.啟動程序 $kernprof -l -v test.py
無需 實際運行項目時刪除@profile,如需單獨測試此函數,直接使用 if __name__=='__main__': 即可,這樣在其他函數引用時,不會執行line_profiler相關代碼。
相關博客:
http://blog.csdn.net/guofangxiandaihua/article/details/77825524