使用line_profiler查看api接口函數每行代碼執行時間


項目情景描述

  在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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM