【读书笔记】 如何进行Python性能分析

2023-05-16

文章目录

  • Python解释器
  • 性能分析方法
    • 1、time计时
    • 2、标准库内建分析工具
    • 3、逐行分析
    • 4、 诊断内存
    • 其他建议
  • 参考目录

Python解释器

python 解释器有很多:CPython、IPython、Jython、PyPy,这些解释器由编译器和虚拟机组成。

虚拟机可以让python的编程者无需关注底层实现(比如要如何为数组分配内存、如何组织内存以及用什么样的顺序将内存传入 CPU),好处是可以直接快速设计出更高层的业务逻辑和算法,缺陷则是要付出性能损失的代价。但python指令层本身就存在优化,所以更好的利用这一层优化(即使用正确的指令顺序),也就可以提高你写的python性能。

其次,python的GIL(全局解释器锁)会影响程序在并行方面的性能。GIL是CPython中的一个概念,它通过计数的方式进行内存管理,实现了一个互斥锁(防止多线程并发执行机器码)。那么在多核CPU上运行时python时,实际用到的可能就是一个单核,其他沦为摆设。如下图所示,三个线程都只有等到前一个释放资源后才能继续运行。因此需要使用标准库的 multiprocessing,numexpr,或分布式计算模型等方法来解决。

GIL 确保 Python 进程一次只能执行一条指令,无论当前有多少个核心。 这意味着即使某些 Python代码可以使用多个核心,在任意时间点仅有一个核心在执行 Python 的指令。

GIL

另一方面,Python 使用了动态类型,且 Python 也并不是一门编译性的
语言。由于代码在运行过程中会发生改变,那么也没办法在编译器层面对代码进行优化。但使用Just-In-Time(JIT)技术可以改善这一问题,实现加速。例如CPython中将python代码注释为C语言类型,还有微软的Pyston等。

性能分析方法

1、time计时

time计时

import time

start_time = time.time()
for i in range(1,1000000):
    x = i*i
end_time = time.time()

print("Spend:{:.4f}".format(end_time-start_time) )

结果:

Spend:0.0618	

装饰器

可以定义一个装饰器来自动测量时间:

from functools import wraps 
def timefn(fn): 
 @wraps(fn) 
 def measure_time(*args, **kwargs): 
 	t1 = time.time() 

使用装饰器:

@timefn 
def calculate_z_serial_purepython(maxiter, zs, cs): 

timeit模块
该模块会禁用垃圾回收机制。 命令行中使用-m timeit的方式就可以调用
指定-n 循环次数和-r 重复次数,如果不指定则默认为n=10,r=5。

python -m timeit -n 5 -r 5 -s "import julia1" "julia1.calc_pure_python(desired_width=1000, 
 max_iterations=300)"

UNIX 的 time
调用python脚本时,命令行前加上 /usr/bin/time -p,使用系统的time。但只能在类UNIX系统下使用。

python脚本:test.py

	import time
	start_time = time.time()
	for i in range(1,1000000):
	    x = i*i
	end_time = time.time()
	print("Finish test.")

运行:/usr/bin/time --verbose python test.py
在UNIX 的 time

打开--verbose 开关可以获得更多输出信息

2、标准库内建分析工具

总共有三个:

  • hotshot
  • cProfile 模块
  • profile 模块

后两者接口是一致的,实现方法不同。profile是纯python实现,而cProfile用C语言钩入 CPython 的虚拟机来测量其每一个函数运行所花费的时间(代价巨大但信息更丰富)。

例子:

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

打印信息:

197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

分析工具
为了更好的分析cProfile得到的结果,可以使用这些模块。

  1. runsnakerun可视化工具:
    在这里插入图片描述

  2. ‎‎pstats分析工具:

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()

# 按照函数名排序,只打印前3行函数的信息, 参数还可为小数,表示前百分之几的函数信息 
p.strip_dirs().sort_stats("name").print_stats(3)

# 按照运行时间和函数名进行排序
p.strip_dirs().sort_stats("cumulative", "name").print_stats(0.5)

# 如果想知道有哪些函数调用了sum_num
p.print_callers(0.5, "sum_num")

# 查看test()函数中调用了哪些函数
p.print_callees("test")

3、逐行分析

line_profiler可以进行逐行分析
pip或者conda下载line_profiler包以后,用@profile装饰器的方式使用。

用修饰器(@profile)标记选中的函数。用 kernprof.py 脚本运行你的代码,被选函数每一行花费的 CPU 时间以及其他信息就会被记录下来。

命令行中运行 kernprof 逐行分析被修饰函数的 CPU 开销:
kernprof -l -v test.py

运行时参数-l 代表逐行分析而不是逐函数分析,-v 用于显示输出。没有-v,你会
得到一个.lprof 的输出文件,回头你可以用 line_profiler 模块对其进行分
析。例 2-6 中,我们会完整运行一遍我们的 CPU 密集型函数

4、 诊断内存

memory_profiler可以诊断内存的用量,操作与上一个包类似,也要先添加@profile在你需要诊断的函数上方,然后运行:
python -m memory_profiler test.py
再通过mprof功能,将生成的统计文件制作成图。

其他建议

1、如果觉得更改代码,每次都要去添加@profile很麻烦,可以考虑使用no-op 修饰器,避免出现Import Error之类的引用错误。
例如:

# memory_profiler 
if 'profile' not in dir(): 
	 def profile(func): 
		 def inner(*args, **kwargs): 
			 return func(*args, **kwargs) 
	return inner

2、要保证测试机器的稳定,例如在 BIOS 上禁用了 TurboBoost,禁用操作系统改写 SpeedStep,不要用笔记本电池而是使用主电源。
3、多次测试,备份数据。

参考目录

[1] Python高性能编程
[2] Realpython
[3] 一份让Python疯狂加速的工具合集!
[4] python性能分析之cProfile模块
[5]The Python Profilers

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【读书笔记】 如何进行Python性能分析 的相关文章

  • 解决android studio 控制台乱码

    双击shift键 xff0c 输入vmoption xff0c 选择Edit Custom CM Options 如果没有配置过 xff0c 就会弹出窗口问是否创建配置文件 xff0c 点击Create xff0c 输入 Dfile enc
  • 无人机学习笔记

    硬件 首先从硬件开始说起把 xff0c 气压计 陀螺仪 磁力计 xff0c 这三个不用说肯定是必备的 xff0c 后面由于开发的需要还添加了激光测距 xff0c 以及光流 但是在开发过程中遇到了很多问题 xff0c 一个一个来说 气压计 气
  • 解决KEIL中ARM编译器不能编译的问题

    keil编译器出现问题 xff0c 根据提示意思就是ARM编译器选择不对的问题 Target 39 Printf 39 uses ARM Compiler 39 V5 06 update 6 build 750 39 which is no
  • linux 内核中strstr函数 功能

    在内核代码中看到strstr函数 xff1a mode 61 strstr boot command line 34 D 34 应该是一个字符串处理函数 xff0c 使用man命令查看下给出如下解释 xff1a SYNOPSIS inclu
  • KPI异常检测资料汇总

    文章目录 0 综述类1 KPI异常检测1 1 经典模型1 1 1 Donut 基于VAE的周期性无监督KPI异常检测1 1 1 1 论文解读1 1 1 2 源码分析 1 12 MAD 基于GANs的时间序列数据多元异常检测 1 2 行业落地
  • jupyter notebook:使用argparse包存在的问题及解决

    argparse模块 argparse是python用于解析命令行参数和选项的标准模块 导入argparse包 span class hljs keyword import span argparse 遇到的问题 parser 61 arg
  • Qt C++和Java相互调用

    Qt C 43 43 和Java相互调用 1 C 43 43 调用Java Test h span class token keyword class span span class token class name Test span s
  • 单片机HAL库使用HAL_UART_Receive_IT

    前言 由于本人第一次尝试开发单片机 xff0c 要实现的功能是信息转发 xff0c 需要调用HAL库方法 xff0c 中断接受信息转发给FPGA xff0c 这里没有用到DMA方式所以不做赘述 xff0c 特此记录分享希望帮到你们 发送信息
  • VLC播放gstreamer pipeline rtp流

    一 xff1a Gstreamer 下载gstreamer 编译等自行百度 pipeline命令 硬编码输出rtp gst launch 1 0 e videotestsrc 34 video x raw format 61 I420 wi
  • 【unity】Multiple plugins with the same name '...'解决方案

    Multiple plugins with the same name 39 ulua 39 found at 39 Assets Plugins uLua 1 22 x86 64 ulua dll 39 and 39 Assets Plu
  • CMAKE 环境变量

    CMAKE CXX FLAGS CMAKE C FLAGS 在cmake脚本中 xff0c 设置编译选项有两种方式 xff1a 1 1 add compile options命令 add compile options命令添加的编译选项是针
  • Gstreamer常见pipeline命令 - 持续更新中

    解码 xff1a xff08 根据码流类型自适应创建相应解码器 xff09 gst launch 1 0 filesrc location 61 home user DCIM Camera VID 20201001 103749 mov q
  • ubuntu18.04 安装包提示没有可安装候选

    sudo apt get install gcc 正在读取软件包列表 完成 正在分析软件包的依赖关系树 正在读取状态信息 完成 没有可用的软件包 gcc xff0c 但是它被其它的软件包引用了 这可能意味着这个缺失的软件包可能已被废弃 xf
  • D435在ROS下的使用

    本人电脑Ubuntu16 04 Ros 为kinetic D435可以用的ros源码下载地址 https github com intel ros realsense releases一定要仔细查看每一个版本基于的sdk的版本号 D435的
  • 在ros下使用D435出现问题ResourceNotFound: realsense2_camera

    在launch的文件内运行roslaunch rs rgbd launch出现错误 xff1a ResourceNotFound realsense2 camera 或运行 roslaunch realsense2 camera rs rg
  • 在ROS中发布IMU数据

    本文主要是来发布sensor msgs Imu类型的消息 xff0c 其中 xff29 xff2d xff55 的数据为虚拟的 xff11 xff0e 在自己的工作空间中创建ros程序包 这个包依靠std msgs roscpp rospy
  • 控制理论学习资料

    DR CAN 傅里叶分析之掐死教程 xff08 完整版 xff09 更新于2014 06 06
  • 卡尔曼滤波原理二:扩展卡尔曼

    1 理论部分 上一篇介绍了线性卡尔曼滤波器 xff0c 当系统为线性高斯模型时 xff0c 滤波器能给出最优的估计 xff0c 但是实际系统总是存在不同程度的非线性 xff0c 如平方 三角关系 开方等 对于非线性系统 xff0c 可以采用
  • PIXHAWK添加自定义消息存储到SD卡

    四旋翼调试阶段总会出现很多难以预见的现象 xff0c 这时为了找到所出问题的原因 xff0c 就需要获得原始相关数据进行分析 xff0c pixhawk代码提供了记录飞行日志的功能 xff0c 能够将飞行中的重要数据存入SD卡中 xff0c
  • reStructuredText介绍

    文档格式编辑 xff0c 目前主流最强大的要是latex xff0c 但是语法太复杂 xff0c 环境要求也多 xff0c 有的时候也是写文档往往选择markdown xff0c 常常怀疑文档编辑的markdown不是亲生的 xff0c 很

随机推荐