python高性能编程 读书笔记
GIL 确保 Python 进程一次只能执行一条指令
====分析工具
cProfile 分析函数耗时
ncalls:表示函数调用的次数;
tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;
percall:(第一个percall)等于 tottime/ncalls;
cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
percall:(第二个percall)即函数运行一次的平均时间,等于 cumtime/ncalls;
filename:lineno(function):每个函数调用的具体信息;
python -m cProfile -s tottime your_program.py ========= import cProfile cp = cProfile.Profile() cp.enable() #中间是你想测的函数 cp.disable() cp.print_stats()
火焰图 pip install flameprof import cProfile # 把需要 profile 的代码放到 pr.enable 和 pr.disable 中间 if __name__ == '__main__': pr = cProfile.Profile() pr.enable() # 开始收集性能分析数据 main() pr.disable() # 停止收集性能分析数据 pr.dump_stats("/statistic/pipe1.prof") # 把当前性能分析的内容写入一个文件 flameprof pipe1.prof > pipe1.svg
针对 Python 可以尝试:cProflile + gprof2dot 而针对 Go 可以使用: pprof + go-torch
if __name__ == "__main__": #参考:https://blog.csdn.net/asukasmallriver/article/details/74356771 import cProfile # 直接把分析结果打印到控制台 cProfile.run("test()") # 把分析结果保存到文件中 cProfile.run("test()", filename="result.out") # 增加排序方式 cProfile.run("test()", filename="result.out", sort="cumulative")
适用面命令行的方式:
# 直接把分析结果打印到控制台 python -m cProfile test.py # 把分析结果保存到文件中 python -m cProfile -o result.out test.py # 增加排序方式 python -m cProfile -o result.out -s cumulative test.py
python提供了一个pstats模块,用来分析cProfile输出的文件内容
import pstats # 创建Stats对象 p = pstats.Stats("result.out") # strip_dirs(): 去掉无关的路径信息 # sort_stats(): 排序,支持的方式和上述的一致 # print_stats(): 打印分析结果,可以指定打印前几行 # 和直接运行cProfile.run("test()")的结果是一样的 p.strip_dirs().sort_stats(-1).print_stats()
=============
line_profiler 逐行分析
heapy 追踪 Python 内存中所有的对象— 这对于消灭奇怪的内存泄漏特别有用
memory_profiler 图的形式展示 RAM 的使用情况随时间的变化
虽然它们不支持改变大小,但是我们可以将两个元组合并成一个新元组。任意两个元组相加始终返回一个新分配的元组,所以复杂度是O(n)
>>> t1 = (1,2,3,4)
>>> t2 = (5,6,7,8)
>>> t1 + t2
(1, 2, 3, 4, 5, 6, 7, 8)
#coding:utf8 from flask import Flask, jsonify import time from functools import wraps from 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 decorator 19 app = 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()
from line_profiler import LineProfiler import random def do_stuff(numbers): s = sum(numbers) l = [numbers[i]/43 for i in range(len(numbers))] m = ['hello'+str(numbers[i]) for i in range(len(numbers))] numbers = [random.randint(1,100) for i in range(1000)] lp = LineProfiler() lp_wrapper = lp(do_stuff) #zcy装饰 lp_wrapper(numbers) # zcy传参 lp.print_stats() #zcy调用
import time
from line_profiler import LineProfiler
def tst(age):
print('tst stst')
time.sleep(1)
print('age',age)
def idokown(name):
print('i love u',name)
time.sleep(2)
i=9*2-4
print(i)
tst(12)
if __name__ == '__main__':
lp = LineProfiler()
lp.add_function(tst) #若没这句话,则在分析结果中没有对tst函数的分析
lp_wrapper = lp(idokown) #装饰idokown
lp_wrapper('zzz') #调用idokown
lp.print_stats() #直接打印结果
# lp.dump_stats('pp.out') 将结果保留到一个文件中
# python3 -m line_profiler pp.out 打印文件中的内容