在Flask中使用line_profiler分析代码性能

背景

当使用Flask进行Web开发,发现接口响应较慢或者超时的时候,我们可以借助性能分析工具line_profiler来查看每行代码的执行时间,从而找到原因。

用法一

定义一个装饰器,将line_profiler相关逻辑封装到装饰器中,在需要分析的接口函数加上此装饰器:

from functools import wraps

from flask import Flask, jsonify
from line_profiler import LineProfiler

app = Flask(__name__)


# 打印接口中每行代码执行的时间
def func_line_time(f):
    @wraps(f)
    def decorator(*args, **kwargs):
        profile = LineProfiler()
        profile_wrap = profile(f)
        result = profile_wrap(*args, **kwargs)
        profile.print_stats()
        return result

    return decorator


@app.route("/")
@func_line_time
def fibonacci():
    a = b = 1
    for _ in range(2, 100):
        a, b = a + b, a
    return jsonify(a)


if __name__ == '__main__':
    app.run()

启动flask应用,再请求接口,可以看到如下输出:

Timer unit: 1e-09 s

Total time: 0.000516835 s
File: /tmp/pycharm_project_154/app.py
Function: fibonacci at line 22

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    22                                           @app.route("/")
    23                                           @func_line_time
    24                                           def fibonacci():
    25         1       1561.0   1561.0      0.3      a = b = 1
    26        99      47691.0    481.7      9.2      for _ in range(2, 100):
    27        98      97969.0    999.7     19.0          a, b = a + b, a
    28         1     369614.0 369614.0     71.5      return jsonify(a)

返回结果中各列的具体含义:

  1. Line:代码行号
  2. Hits:表示此行代码运行的次数
  3. Time:此行代码运行的总时间
  4. Per Hits:此行代码运行一次的平均时间
  5. % Time:此行代码运行时间占总时间的百分比

用法二

使用kernprof工具,在需要分析的函数前加上装饰器@profile,执行kernprof -l app.py,等接口响应完成后停止flask,kernprof会将分析结果写入app.py.lprof

from flask import Flask, jsonify
from line_profiler.explicit_profiler import profile

app = Flask(__name__)


@app.route("/")
@profile
def fibonacci():
    a = b = 1
    for _ in range(2, 100):
        a, b = a + b, a
    return jsonify(a)


if __name__ == '__main__':
    app.run()

# 执行
kernprof -l app.py    # 执行完后将分析结果写入app.py.lprof
kernprof -l -v app.py # 写入app.py.lprof后打印出来

查看app.py.lprof的内容:

$ python -m line_profiler app.py.lprof
Timer unit: 1e-06 s

Total time: 0.000521002 s
File: app.py
Function: fibonacci at line 7

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           @app.route("/")
     8                                           @profile
     9                                           def fibonacci():
    10         1          1.7      1.7      0.3      a = b = 1
    11        99         47.0      0.5      9.0      for _ in range(2, 100):
    12        98         78.0      0.8     15.0          a, b = a + b, a
    13         1        394.3    394.3     75.7      return jsonify(a)

用法三

使用flask应用上下文模拟接口请求过程,无需启动flask应用:

from flask import Flask, jsonify
from line_profiler import LineProfiler

app = Flask(__name__)


@app.route("/")
def fibonacci():
    a = b = 1
    for _ in range(2, 100):
        a, b = a + b, a
    return jsonify(a)


if __name__ == '__main__':
    with app.app_context():
        profile = LineProfiler()
        profile.add_function(fibonacci)
        profile.enable()
        result = fibonacci()
        profile.disable()
        print(result.get_json())
        profile.print_stats()

如果有用到请求上下文中的对象(比如request),可以使用test_client()来模拟:

from flask import Flask, jsonify, request
from line_profiler import LineProfiler

app = Flask(__name__)


@app.route('/')
def fibonacci():
    n = int(request.args.get('n'))
    a = b = 1
    for _ in range(2, n):
        a, b = a + b, a
    return jsonify(a)


if __name__ == '__main__':
    with app.app_context(), app.test_client() as client:
        profile = LineProfiler()
        profile.add_function(fibonacci)
        profile.enable()
        result = client.get('/?n=100')
        profile.disable()
        print(result.get_json())
        profile.print_stats()

和前两种比较而言,这种方法不用修改原有代码,无需启动flask应用,也省去了请求接口的步骤,更加方便。

你可能感兴趣的:(flask,flask,python,line_profiler,代码分析)