大家好,欢迎来到Crossin的编程教室!
虽然很多人都认为Python是一个“慢”语言,但其实很多时候,导致程序慢的原因并不是语言的锅,而是代码写得不够好。所以在程序运行过程中,如果发现运行时间太长或者内存占用过大,就需要对程序的执行过程进行一些监测,找到有问题的地方,进行优化。今天我们就来分享一些平时能用上的Python性能分析工具。
memory_profiler是监控python进程的神器,只需要在函数加一个装饰器就可以输出每行代码的内存使用情况
安装:
pip install memory_profiler
使用:
import time@profiledef my_func(): a = [1] * (10 ** 6) b = [2] * (2 * 10 ** 7) time.sleep(10) del b del a print "+++++++++"if __name__ == '__main__': my_func()
输出:
$ python -m memory_profiler del3.py+++++++++Filename: del3.pyLine # Mem usage Increment Line Contents================================================ 10.293 MiB 0.000 MiB @profile def my_func(): 17.934 MiB 7.641 MiB a = [1] * (10 ** 6) 170.523 MiB 152.590 MiB b = [2] * (2 * 10 ** 7) 170.527 MiB 0.004 MiB time.sleep(10) 17.938 MiB -152.590 MiB del b 10.305 MiB -7.633 MiB del a 10.309 MiB 0.004 MiB print "+++++++++"
import timeitimport timedef my_func(): time.sleep(1) return sum([1,2,3])result = timeit.timeit(my_func, number=5)print(result)
在Jupyter Notebook中,可以通过%%timeit
魔法命令测试cell中代码的运行时间
%%timeitimport timedef my_func(): time.sleep(1) return sum([1,2,3])result = timeit.timeit(my_func, number=5)print(result)
Python 中的装饰器可以在其他函数不需要改动任何代码的情况下增加额外功能,经常用在,插入日志、性能测试、权限校验等场景中。我们可以将计时功能封装成一个装饰器,方便复用。
from functools import wrapsimport timedef timeit(func): @wraps(func) def deco(): start = time.time() res = func() end = time.time() delta = end - start print("Wall time ", delta) return res return deco
使用:
@timeitdef my_func(): # do something time.sleep(3) pass
输出:
Wall time: 3
如果我们除了想知道代码整体的运行时间之外,还要精确分析每行代码的运行时间,那python的 line_profiler 模块就可以帮到你啦!line_profiler 可以用来测试函数每行代码的响应时间等情况。为了使用方便,可以将line_profiler 相关函数封装在装饰器中进行使用,这样在接口请求时,则会执行此装饰器并打印出结果。
安装:
pip install line_profiler
使用:
from flask import Flask, jsonifyimport timefrom functools import wrapsfrom line_profiler import LineProfiler# 查询接口中每行代码执行的时间def func_line_time(f): @wraps(f) def decorator(*args, **kwargs): func_return = f(*args, **kwargs) lp = LineProfiler() lp_wrap = lp(f) lp_wrap(*args, **kwargs) lp.print_stats() return func_return return decoratorapp = Flask(__name__)@app.route('/line_test') @func_line_time def line_test(): for item in range(5): time.sleep(1) for item in xrange(5): time.sleep(0.5) return jsonify({'code':200}) if __name__=='__main__': app.run()
输出:
* Running on http://127.0.0.1:5000/Timer unit: 1e-06 sTotal time: 7.50827 sFile: /home/rgc/baidu_eye/carrier/test/flask_line_profiler_test.pyFunction: line_test at line 22Line # Hits Time Per Hit % Time Line Contents============================================================== @app.route('/line_test') @func_line_time def line_test(): 6 33.0 5.5 0.0 for item in range(5): 5 5005225.0 1001045.0 66.7 time.sleep(1) 6 31.0 5.2 0.0 for item in xrange(5): 5 2502696.0 500539.2 33.3 time.sleep(0.5) 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 -
相较于上面的代码运行时间测试工具,pyheat 通过matplotlib 的绘制热力图来展现代码的运行时间,显得更为直观
pip install py-heat
使用方法:
pyheat --out image_file.png
heartrate 也是一个可视化的监测工具,可以像监测心率一样追踪程序运行,通过web页面可视化Python程序的执行过程。
img左侧数字表示每行代码被触发的次数。长方框表示最近被触发的代码行——方框越长表示触发次数越多,颜色越浅表示最近被触发次数越多。该工具记录的是每行代码执行的次数,
而不是具体执行时间,在性能调试的时候有些鸡肋
安装:
pip install --user heartrate
使用:
import heartratefrom heartrate import trace, filesheartrate.trace(browser=True)trace(files=files.path_contains('my_app', 'my_library'))
以上就是几款常用的Python性能优化工具。但工具只是辅助,核心还是需要写代码的人要有代码优化的意识以及对语言和代码的深入理解。这是一个长期积累的过程。坚持读代码、写代码,你的代码性能自然也会随着你的能力不断提高!
作者:Alpha 3
来源:数据科学杂谈
_往期文章推荐_
测一测,你写的代码性能好吗?