Python性能分析优化及测试

  • 写在前面
  • CPU分析工具
    • 简单的time方法以及包装成的修饰器
    • timeit
    • UNIX的time命令进行简单的计时
    • cProfile:分析每个函数运行花费的时间
    • line_profiler:逐行分析
  • 内存分析工具
    • memory_profiler: 内存用量诊断工具
    • heapy:内存堆调查工具
  • 用dis模块检查CPython字节码

写在前面

分析工作的一个好的方式是在分析之前对代码的各部分的运行速度和内存消耗情况做一个假设或者预判,然后结合分析工具的分析结果验证或者纠正假设,不断提高对代码的分析能力。

CPU分析工具

简单的time方法以及包装成的修饰器

Python性能分析最简单的方法是通过内置time模块的测量,然后打印出来,但是这种方法只适用于简短的调查,用的过多会比较杂乱。如下:

t1= time.time()
result = fn(*args, **kwargs)
t2 = time.time()
print('@timefn:' + fn.func_time + 'took' + str(t2-t1) + 'second')

比较干净的方法是使用修饰器,在被需要调查的函数定义上面增加一行修饰语句。使用这个修饰器的开销很小,但是成千上万次会变得引人注意。

from functools import wrapsdef timefn(fn):@wraps(fn)def measure_time(*args, **kwargs): # *arg数量可变的位置参数,**kwargs数量可变的键值对参数t1= time.time()result = fn(*args, **kwargs)t2 = time.time()print('@timefn:' + fn.func_time + 'took' + str(t2-t1) + 'second')return resultreturn measure_time

这里定义了一个新函数timefn,它一个函数fn为参数,使用@wraps(fn)将函数名和docstring暴露给fn的调用者。

timeit

timeit一般用来测量简单语句的执行速度,作为一种辅助分析手段。timeit模块暂时禁用了垃圾收集器,如果测试代码中调用了垃圾收集器会影响到执行速度。方法:

python -m timeit -n 5 -r 5 -s "import modulename" "function(arg1 = **, arg2 = **)"

‘ -s’用来导入被测函数的模块;‘-n’指定循环次数,取平均数;‘-r’为重复次数,选平均数中的最好结果。这种方法与IPython中‘%time’方法类似。

UNIX的time命令进行简单的计时

使用UNIX操作系统的标准系统功能记录程序执行所耗费的各方面时间,且不在意代码的内部结构。使用方法:

/usr/bin/time -p python name.py

输出结果分三个部分:real记录了整体的耗时, user记录了CPU花在任务上的时间,但不包括内核函数耗费的时间, sys记录了内核函数耗费的时间。user和sys相加的和就得到CPU花费的总时间,而这个时间和real的差可能就是花费在等待IO上,也可能是系统正忙着运行其他任务因此影响了测量。另外比较有用的方法是用‘–verbose’来获得更多输出信息。

/usr/bin/time -verbose python name.py

打印的信息中很有用的一项是‘Major(requiring I/O) page faults’,因为它指示了内存缺页引发的性能惩罚。

cProfile:分析每个函数运行花费的时间

cProfile是一个标准库内建工具,通过钩入CPython虚拟机来测量每一个函数所花费的时间,这一技术会引入额外的巨大开销。执行如下命令,cProfile会将输出直接打印到屏幕。

python -m cProfile -s cumulative name.py

‘-s’的意义是设置cProfile的分析结果对每个函数累计花费的时间进行排序。然后还可以生成统计文件,然后通过Python进行分析。

python - m cProfile - o profile.stats name.py
import pstats
p = pstats.Stats("profile.stats")
p.sort_stats("cumulative")
p.print_stats()

另外,我们还可以通过‘print_callers()’和‘print_callees()’方法打印出调用者和被调用者的信息。

p.print_callers()
p.print_callees()

line_profiler:逐行分析

line_profile可以对函数进行组行分析,应该先用cProfile找到最需要分析的函数,然后用line_profile对函数进行分析,通过pip安装。

pip install line_profiler

使用方法:先通过修饰器‘@profile’标记需要分析的函数,然后运行如下命令。

kernprof -l -v name.py

'-l’代表组行分析而不是逐个函数分析, ‘-v’代表显示输出,分析过程会产生一个后缀为’.lprof’的文件。得到结果观察哪条语句执行占用的时间最多,然后进行进一步分析,尝试更换执行顺序、调整算法、编译和类型指定等方法来优化,并用后续的测试进行验证。可以运用‘%timeit’来对比测量一些语句的效率;Python语句的评估次序是从左至右且支持短路,可以将执行开销大的语句放在右边。

内存分析工具

memory_profiler: 内存用量诊断工具

memory_profile包最好有psutil包的支持,二者皆可以通过pip安装。

pip install psutil memory_profiler

memory_profiler的对性能的影响很大(10-100倍的降速,比line_profiler的效率还低),所以最好将测试局限在一个较小的问题上,或者在代码成长的早期进行分析。使用的方法分两步,第一步是在源代码中用‘@profile’对需要分析的函数进行标记,第二步是调用memory_profiler模块进行分析。

python -m memory_profiler code_need_analyse.py

IPython中可以使用‘%memit’魔法函数来测量某些语句的RAM使用情况,工作方式类似于‘%timeit’
特别说明:
在处理内存分配时,情况并不像CPU占有率那么直截了当,通常一个进程将内存超额分配给本地内存池并在空闲时使用会更有效率,因为一次内存分配的操作非常昂贵;
另外,垃圾收集不会立即执行,所以对象被销毁后依然会存在垃圾收集池中一段时间;
这些技术的后或是很难真正了解一个Python程序内部的内存使用和释放情况,因为当从进程外部观察时,某一段代码可能不会分配固定数量的内存,观察多行代码的内存占有趋势可能比只观察一行代码更有参考价值。

heapy:内存堆调查工具

借助heapy可以深入解释器内部查看内存堆中有多少对象被使用以及它们是否被垃圾收集时,是解决内存泄漏(可能由于某个对象的引用隐藏于一个复杂系统中)的有效工具;还可以通过审查去考察是否如预期的那样生成对象。使用heapy需要通过pip安装guppy包。

pip install guppy

使用方法:

def calc_pure_python(draw_output, desired_width, max_iterations):...while xcoord < x2:x.append(xcoord)xcoord += x_stepfrom guppy import hpy; hp = hpy()print("heapy after creating y and x lists of floats")h = hp.heap()print(h) printzs = []cs = []for ycoord in y:for xcoord in x:zs.append(complex(xcoord, ycoord))zs.append(complex(c_real, c_imag))print("heapy after creating zs and cs using complex numbers")h = hp.heap()print(h)

用dis模块检查CPython字节码

dis模块是Pyhon内建的包,通过传给它一段代码或者一个模块可以查看到基于栈的CPython虚拟机运行的字节码,增强对Python代码模型的理解,可以了解到为什么某些编码风格会比其他的更快,同时还能帮助使用Cython这样的工具,他跳出了Python的范畴,能够生成C代码。使用方法:

import dis
dis.dis(module or function name)

Python性能分析优化及测试相关推荐

  1. python性能分析(一)——使用timeit给你的程序打个表吧

    前言 我们可以通过查看程序核心算法的代码,得知核心算法的渐进上界或者下界,从而大概估计出程序在运行时的效率,但是这并不够直观,也不一定十分靠谱(在整体程序中仍有一些不可忽略的运行细节在估计时被忽略了) ...

  2. python性能分析与优化

    性能分析: 1.种类: 基于事件的性能分析通过收集程序执行过程中的具体事件进行工作,每个调用都会触发,输出数据量大,精度高def profiler(frame, event, arg):print ' ...

  3. Python性能分析利器pyinstrument讲解

    一.前言 程序的性能也是非常关键的指标,很多时候你的代码跑的快,更能够体现你的技术.最近发现很多小伙伴在性能分析的过程中都是手动打印运行时间的方式来统计代码耗时的: import datetime s ...

  4. python性能分析工具总结

    性能分析工具的使用 cProfile 介绍 它是一种确定性的性能分析器,提供了一组API帮助开 发者收集Python程序运行的信息,更确切地说,是统计每个函数消耗的 CPU时间.同时它还提供了其他细节 ...

  5. python性能分析工具模块_python——关于Python Profilers性能分析器

    1. 介绍性能分析器 profiler是一个程序,用来描述运行时的程序性能,并且从不同方面提供统计数据加以表述.Python中含有3个模块提供这样的功能,分别是cProfile, profile和ps ...

  6. Python 性能分析入门指南

    为什么80%的码农都做不了架构师?>>>    在岭南六少博客找到的好东西. 注: 本文的原作者是 Huy Nguyen ,原文地址为 A guide to analyzing Py ...

  7. Python性能分析入门——cProfile、可视化、逐行分析、内存分析

    文章目录 简介 cProfile PyCharm 可视化 安装 gprof2dot SnakeViz PyCallGraph 逐行分析 内存分析 内存堆分析 其他 遇到的坑 参考文献 简介 通过性能分 ...

  8. Python性能分析 (Profiling)

    此页由Linux Wiki用户 Chenxing于2012年3月21日 (星期三) 07:02的最后更改. 提示:此文已超过 2 年(960 天)未更新,如发现内容过时或有误,欢迎改进:) 性能分析( ...

  9. CPU性能分析优化套路

    目录 一.CPU性能指标 1.CPU 使用率 2.平均负载 3.进程上下文切换 4.CPU 缓存的命中率 二.CPU性能工具 1.性能工具 2.从性能指标找工具(重点是:思路) 3.从工具理解性能指标 ...

最新文章

  1. 虚拟化技术的概述及使用
  2. ubuntu 安装intel iofrt 和icc编译器
  3. 隐马尔可夫模型 HMM 原理及实现
  4. [Json] C#ConvertJson|List转成Json|对象|集合|DataSet|DataTable|DataReader转成Json (转载)...
  5. 前端学习(955):移动端特效导读
  6. 机器学习(三)k均值聚类
  7. java2实用教程 (课后习题总结)
  8. 风格迁移篇-AdaIN --使用自适应实例规范化实时传输任意样式
  9. ltspice滑动变阻器在哪_NB物理创新课堂|变阻器
  10. 【学习笔记】seckill-秒杀项目--(6)秒杀功能
  11. 基于PLC的搬运机器手控制系统设计
  12. USACO题解——Section 1.2——Greedy Gift Givers
  13. java哥验证德巴赫猜想,C语言验证哥德巴赫猜想
  14. fcpx:火焰特效坍塌爆炸特效高清视频素材Vfx-Starter-Pack
  15. cydia软件路径_在Cydia中提取Deb格式安装包文件
  16. 结构变异( SV )分析介绍
  17. VMware公司揭开NSX半边面纱,旨在推动DevOps能力
  18. ios客户端学习笔记(八):iOS客户端的推送通知
  19. 基于引擎开发HTML5游戏实战(二)---游戏剧本
  20. 【代码随想录】二刷-数组

热门文章

  1. matlab程序模拟微信抢红包,js仿微信抢红包功能
  2. 新冠病毒阴谋论报告:有观点甚至认为是盖茨基金会制造的
  3. 蓝桥杯第九届省赛B组c/c++
  4. Hive Full Join多个表与Union All多个表
  5. 坚果云和百度云的对比
  6. hdu3966_树链剖分
  7. 用非正式沟通减少需求和交互的矛盾
  8. 项目实战!用爬虫和Flask打造属于自己的电影网站
  9. 洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值
  10. PHP银联在线支付接口开发日志