python程序分析,用Python编写分析Python程序性能的工具的教程

用Python编写分析Python程序性能的工具的教程

来源:中文源码网    浏览: 次    日期:2018年9月2日

【下载文档:  用Python编写分析Python程序性能的工具的教程.txt 】

(友情提示:右键点上行txt文档名->目标另存为)

用Python编写分析Python程序性能的工具的教程 虽然并非你编写的每个 Python 程序都要求一个严格的性能分析,但是让人放心的是,当问题发生的时候,Python 生态圈有各种各样的工具可以处理这类问题。

分析程序的性能可以归结为回答四个基本问题: 正运行的多快

速度瓶颈在哪里

内存使用率是多少

内存泄露在哪里下面,我们将用一些神奇的工具深入到这些问题的答案中去。

用 time 粗粒度的计算时间

让我们开始通过使用一个快速和粗暴的方法计算我们的代码:传统的 unix time 工具。

$ time python yourprogram.py

real 0m1.028s

user 0m0.001s

sys 0m0.003s

三个输出测量值之间的详细意义在这里 stackoverflow article,但简介在这: real — 指的是实际耗时

user — 指的是内核之外的 CPU 耗时

sys — 指的是花费在内核特定函数的 CPU 耗时你会有你的应用程序用完了多少 CPU 周期的即视感,不管系统上其他运行的程序添加的系统和用户时间。

如果 sys 和 user 时间之和小于 real 时间,然后你可以猜测到大多数程序的性能问题最有可能与 IO wait 相关。

用 timing context 管理器细粒度的计算时间

我们下一步的技术包括直接嵌入代码来获取细粒度的计时信息。下面是我进行时间测量的代码的一个小片段

timer.py

import time

class Timer(object):

def __init__(self, verbose=False):

self.verbose = verbose

def __enter__(self):

self.start = time.time()

return self

def __exit__(self, *args):

self.end = time.time()

self.secs = self.end - self.start

self.msecs = self.secs * 1000 # millisecs

if self.verbose:

print 'elapsed time: %f ms' % self.msecs

为了使用它,使用 Python 的 with 关键字和 Timer 上下文管理器来包装你想计算的代码。当您的代码块开始执行,它将照顾启动计时器,当你的代码块结束的时候,它将停止计时器。

这个代码片段示例:

from timer import Timer

from redis import Redis

rdb = Redis()

with Timer() as t:

rdb.lpush("foo", "bar")

print "=> elasped lpush: %s s" % t.secs

with Timer() as t:

rdb.lpop("foo")

print "=> elasped lpop: %s s" % t.secs

为了看看我的程序的性能随着时间的演化的趋势,我常常记录这些定时器的输出到一个文件中。

使用 profiler 逐行计时和分析执行的频率

罗伯特·克恩有一个不错的项目称为 line_profiler , 我经常使用它来分析我的脚本有多快,以及每行代码执行的频率:

为了使用它,你可以通过使用 pip 来安装它:

pip install line_profiler

安装完成后,你将获得一个新模块称为 line_profiler 和 kernprof.py 可执行脚本。

为了使用这个工具,首先在你想测量的函数上设置 @profile 修饰符。不用担心,为了这个修饰符,你不需要引入任何东西。kernprof.py 脚本会在运行时自动注入你的脚本。

primes.py@profile

def primes(n):

if n==2:

return [2]

elif n<2:

return []

s=range(3,n+1,2)

mroot = n ** 0.5

half=(n+1)/2-1

i=0

m=3

while m <= mroot:

if s[i]:

j=(m*m-3)/2

s[j]=0

while js[j]=0

j+=m

i=i+1

m=2*i+3

return [2]+[x for x in s if x]

primes(100)

一旦你得到了你的设置了修饰符 @profile 的代码,使用 kernprof.py 运行这个脚本。

kernprof.py -l -v fib.py

-l 选项告诉 kernprof 把修饰符 @profile 注入你的脚本,-v 选项告诉 kernprof 一旦你的脚本完成后,展示计时信息。这是一个以上脚本的类似输出:Wrote profile results to primes.py.lprof

Timer unit: 1e-06 s

File: primes.py

Function: primes at line 2

Total time: 0.00019 s

Line # Hits Time Per Hit % Time Line Contents

==============================================================

2 @profile

3 def primes(n):

4 1 2 2.0 1.1 if n==2:

5 return [2]

6 1 1 1.0 0.5 elif n<2:

7 return []

8 1 4 4.0 2.1 s=range(3,n+1,2)

9 1 10 10.0 5.3 mroot = n ** 0.5

10 1 2 2.0 1.1 half=(n+1)/2-1

11 1 1 1.0 0.5 i=0

12 1 1 1.0 0.5 m=3

13 5 7 1.4 3.7 while m <= mroot:

14 4 4 1.0 2.1 if s[i]:

15 3 4 1.3 2.1 j=(m*m-3)/2

16 3 4 1.3 2.1 s[j]=0

17 31 31 1.0 16.3 while j18 28 28 1.0 14.7 s[j]=0

19 28 29 1.0 15.3 j+=m

20 4 4 1.0 2.1 i=i+1

21 4 4 1.0 2.1 m=2*i+3

22 50 54 1.1 28.4 return [2]+[x for x

寻找 hits 值比较高的行或是一个高时间间隔。这些地方有最大的优化改进空间。

它使用了多少内存?

现在我们掌握了很好我们代码的计时信息,让我们继续找出我们的程序使用了多少内存。我们真是非常幸运, Fabian Pedregosa 仿照 Robert Kern 的 line_profiler 实现了一个很好的内存分析器 [memory profiler][5]。

首先通过 pip 安装它:

$ pip install -U memory_profiler

$ pip install psutil

在这里建议安装 psutil 是因为该包能提升 memory_profiler 的性能。

想 line_profiler 一样, memory_profiler 要求在你设置 @profile 来修饰你的函数:

@profile

def primes(n):

...

...

运行如下命令来显示你的函数使用了多少内存:

$ python -m memory_profiler primes.py

一旦你的程序退出,你应该可以看到这样的输出:

Filename: primes.py

Line # Mem usage Increment Line Contents

==============================================

2 @profile

3 7.9219 MB 0.0000 MB def primes(n):

4 7.9219 MB 0.0000 MB if n==2:

5 return [2]

6 7.9219 MB 0.0000 MB elif n<2:

7 return []

8 7.9219 MB 0.0000 MB s=range(3,n+1,2)

9 7.9258 MB 0.0039 MB mroot = n ** 0.5

10 7.9258 MB 0.0000 MB half=(n+1)/2-1

11 7.9258 MB 0.0000 MB i=0

12 7.9258 MB 0.0000 MB m=3

13 7.9297 MB 0.0039 MB while m <= mroot:

14 7.9297 MB 0.0000 MB if s[i]:

15 7.9297 MB 0.0000 MB j=(m*m-3)/2

16 7.9258 MB -0.0039 MB s[j]=0

17 7.9297 MB 0.0039 MB while j18 7.9297 MB 0.0000 MB s[j]=0

19 7.9297 MB 0.0000 MB j+=m

20 7.9297 MB 0.0000 MB i=i+1

21 7.9297 MB 0.0000 MB m=2*i+3

22 7.9297 MB 0.0000 MB return [2]+[x for x in s if x]

line_profiler 和 memory_profiler 的 IPython 快捷命令

line_profiler 和 memory_profiler 一个鲜为人知的特性就是在 IPython 上都有快捷命令。你所能做的就是在 IPython 上键入以下命令:

%load_ext memory_profiler

%load_ext line_profiler

这样做了以后,你就可以使用魔法命令 %lprun 和 %mprun 了,它们表现的像它们命令行的副本,最主要的不同就是你不需要给你需要分析的函数设置 @profile 修饰符。直接在你的 IPython 会话上继续分析吧。In [1]: from primes import primes

In [2]: %mprun -f primes primes(1000)

In [3]: %lprun -f primes primes(1000)

这可以节省你大量的时间和精力,因为使用这些分析命令,你不需要修改你的源代码。

哪里内存溢出了?

cPython的解释器使用引用计数来作为它跟踪内存的主要方法。这意味着每个对象持有一个计数器,当增加某个对象的引用存储的时候,计数器就会增加,当一个引用被删除的时候,计数器就是减少。当计数器达到0, cPython 解释器就知道该对象不再使用,因此解释器将删除这个对象,并且释放该对象持有的内存。

内存泄漏往往发生在即使该对象不再使用的时候,你的程序还持有对该对象的引用。

最快速发现内存泄漏的方式就是使用一个由 Marius Gedminas 编写的非常好的称为 [objgraph][6] 的工具。

这个工具可以让你看到在内存中对象的数量,也定位在代码中所有不同的地方,对这些对象的引用。

开始,我们首先安装 objgraph

pip install objgraph

一旦你安装了这个工具,在你的代码中插入一个调用调试器的声明。

import pdb; pdb.set_trace()

哪个对象最常见

在运行时,你可以检查在运行在你的程序中的前20名最普遍的对象

(pdb) import objgraph

(pdb) objgraph.show_most_common_types()

MyBigFatObject 20000

tuple 16938

function 4310

dict 2790

wrapper_descriptor 1181

builtin_function_or_method 934

weakref 764

list 634

method_descriptor 507

getset_descriptor 451

type 439

哪个对象被增加或是删除了?

我们能在两个时间点之间看到哪些对象被增加或是删除了。

(pdb) import objgraph

(pdb) objgraph.show_growth()

.

.

.

(pdb) objgraph.show_growth() # this only shows objects that has been added or deleted since last show_growth() call

traceback 4 +2

KeyboardInterrupt 1 +1

frame 24 +1

list 667 +1

tuple 16969 +1

这个泄漏对象的引用是什么?

继续下去,我们还可以看到任何给定对象的引用在什么地方。让我们以下面这个简单的程序举个例子。

x = [1]

y = [x, [x], {"a":x}]

import pdb; pdb.set_trace()

为了看到持有变量 X 的引用是什么,运行 objgraph.show_backref() 函数:

(pdb) import objgraph

(pdb) objgraph.show_backref([x], filename="/tmp/backrefs.png")

该命令的输出是一个 PNG 图片,被存储在 /tmp/backrefs.png,它应该看起来像这样:

backrefs (1)

盒子底部有红色字体就是我们感兴趣的对象,我们可以看到它被符号 x 引用了一次,被列表 y 引用了三次。如果 x 这个对象引起了内存泄漏,我们可以使用这种方法来追踪它的所有引用,以便看到为什么它没有被自动被收回。

回顾一遍,objgraph 允许我们: 显示占用 Python 程序内存的前 N 个对象

显示在一段时期内哪些对象被增加了,哪些对象被删除了

显示我们脚本中获得的所有引用Effort vs precision

在这篇文章中,我展示了如何使用一些工具来分析一个python程序的性能。通过这些工具和技术的武装,你应该可以获取所有要求追踪大多数内存泄漏以及在Python程序快速识别瓶颈的信息。

和许多其他主题一样,运行性能分析意味着要在付出和精度之间的平衡做取舍。当有疑问是,用最简单的方案,满足你当前的需求。

亲,试试微信扫码分享本页! *^_^*

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tina中信号带宽_关于通频带,3dB带宽,三阶截点和1dB压缩点,截止频率,频率范围,带宽,特征频率(中心频率),截止频率和增益(db)...

1、通频带通频带用于衡量放大电路对不同频率信号的放大能力。由于放大电路中电容、电感及半导体器件结电容等电抗元件的存在&#xff0c;在输入信号频率较低或较高时&#xff0c;放大倍数的数值会下降并产生相移。通常情况下&#xff0c;放大电路只适用于放大某一个特定频率范围…

php+控制器+数据库,Laravel5.1数据库连接、创建数据库、创建model及创建控制器的方法_PHP...

本文实例讲述了Laravel5.1数据库连接、创建数据库、创建model及创建控制器的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;前言&#xff1a;laravel创建数据库&#xff0c;实际可以手动创建&#xff0c;如古老的phpmyadmin 等均可以。一、数据库连接&#xff1a…

64位百度云 catia v6_福利缩水:百度网盘决定收回部分储存空间

近日&#xff0c;百度网盘公众号对外发布公告称&#xff0c;希望通过合理的资源调配&#xff0c;提升闲置空间使用率&#xff0c;让更多有切实需求的用户享受到优质、稳定、安全的个人云存储服务。因此&#xff0c;对百度网盘的存储空间方案做出调整。具体来看&#xff0c;2018…

物流配送系统设计java,ZigBee物流配送系统设计

目前生产系统的物流配送大部分仍处于较落后的状态&#xff0c;使用单位有物料需求时通过电话或邮件与配送单位进行沟通&#xff0c;这种方式存在沟通不及时和缺少数据记录的缺陷。在出现缺料问题时造成无法追究问题的责任单位&#xff0c;容易出现推脱等问题&#xff0c;对管理…

互联网产品生命周期_我市扎实推进全生命周期公共法律服务产品研发

近日&#xff0c;江苏省司法厅公布全省企业全生命周期公共法律服务产品研发评选活动结果&#xff0c;我市司法局、公证处报送的“区块链公证赋强平台”产品&#xff0c;以总分第一的好成绩荣获全省一等奖。近年来&#xff0c;市司法局充分发挥司法行政职能作用&#xff0c;持续…

php本地文件打包代码,PHP实战:几行代码轻松实现PHP文件打包下载zip

《PHP实战&#xff1a;几行代码轻松实现PHP文件打包下载zip》要点&#xff1a;本文介绍了PHP实战&#xff1a;几行代码轻松实现PHP文件打包下载zip&#xff0c;希望对您有用。如果有疑问&#xff0c;可以联系我们。PHP应用//获取文件列表function list_dir($dir){$result arra…

python的django项目中怎么添加app_django下如何创建多个app并设置urls

1、创建第二个app假设我们项目P下面已经有了一个默认的app&#xff0c;名字是app1。现在我想创建第二个app&#xff0c;名字时app2。进入pychram下的Terminal中&#xff0c;运行命令&#xff1a;python manage.py startapp app2此外&#xff0c;我在每个app下都建立一个urls.py…

oracle监听启动命令6,[转] oracle 监听

启动监听&#xff1a;lsnrctl start查看监听&#xff1a;lsnrctl status停止监听&#xff1a;lsnrctl stop1、oracle 数据服务器包括&#xff1a;实例进程和数据库&#xff1b;实例进程包括&#xff1a;memory structure(sga)以及background process(pmon(进程监控)、smon(系统…

stripfxg php,zzcms v8.2 中的众多cve分析

看了一下最近的cve列表&#xff0c;发现有大佬怒刷了好多个cve&#xff0c;这个zzcms都快被审穿了&#xff0c;所以跟进学习一下CMS背景本文跟踪的这个cms&#xff0c;属于一个开源招商网站管理系统&#xff0c;属于比较小的cms&#xff0c;所以很多地方写的不是很完善&#xf…

python捕获异常装饰器_python异常装饰器--比较全的版本了

#异常捕获装饰器(亦可用于类方法)def try_except_log(fNone, max_retries: int 5, delay: (int, float) 1, step: (int, float) 0,exceptions: (BaseException, tuple, list) BaseException, sleeptime.sleep,processNone, validateNone, callbackNone, defaultNone):"&…

matlab weibpdf函数,matlab建模常用函数

附录Ⅰ 工具箱函数汇总Ⅰ.1 统计工具箱函数表Ⅰ-1 概率密度函数函数名 对应分布的概率密度函数betapdf 贝塔分布的概率密度函数binopdf 二项分布的概率密度函数chi2pdf 卡方分布的概率密度函数exppdf 指数分布的概率密度函数fpdf f分布的概率密度函数gampdf 伽玛分布的概率密度…

拉普拉斯变换_拉普拉斯变换——奇妙的数学

无奈学不会工程数学中的拉普拉斯变换&#xff0c;没办法去感知他的存在形式&#xff0c;在YOUTOBE上看到一个讲解拉普拉斯变换的视频&#xff0c;好像懂了些&#xff0c;分享给同样迷茫的小伙伴&#xff0c;下载的时候是有字幕的&#xff0c;发到知乎上就没字幕了&#xff0c;英…

linux下计算目录文件和,统计Linux 中文件和文件夹/目录的数量(示例代码)

嗨&#xff0c;伙计们&#xff0c;今天我们再次带来一系列可以多方面帮助到你的复杂的命令。 通过操作命令&#xff0c;可以帮助您计数当前目录中的文件和目录、递归计数&#xff0c;统计特定用户创建的文件列表等。在本教程中&#xff0c;我们将向您展示如何使用多个命令&…

没有足够的值_元丰通宝值多少钱吗?市场价值如何?有没有足够的收藏空间?...

元丰通宝是宋代神宗年间发行的&#xff0c;那么你知道现在元丰通宝值多少钱吗&#xff1f;市场价值如何&#xff1f;有没有足够的收藏空间&#xff1f;宋代虽然没有强大的军事实力&#xff0c;但其国内经济水平得到了发展&#xff0c;在许多朝代都处于领先地位。在元丰通宝的铸…

Linux不能读取目录,关于Linux上面无法读取资源目录下文件的问题

一开始我的代码是这样子的,读取本地子路径下的json文件代码运行的时候,在window是可以正常的Overridepublic String getBannerStr() {String str "";try {Resource resource new ClassPathResource("json/abc.json");File file resource.getFile();str …

jsp中java代码无效_来杯咖啡,教你如何优雅的在java中统计代码块耗时

推荐阅读&#xff1a;Sping源码RedisNginxMySQL等七篇实战技术文档&#xff0c;阿里大佬推荐阿里内部&#xff1a;2020年全技术栈文档PPT分享&#xff0c;(万粉总结&#xff0c;回馈粉丝)在我们的实际开发中&#xff0c;多多少少会遇到统计一段代码片段的耗时的情况&#xff0c…

linux 随机抽取文件,shell 随机从文件中抽取若干行的实现方法

shuf -n5 main.txtsort -R main.txt | head -5awk -vN5 -vC"wc -l file" BEGIN{srand();while(nwhile read line;do echo "$line $RANDOM";done < main.txt | sort -k2,2n| awk NR<5{print $1}shuf 命令的选项&#xff1a;-e, --echo &#xff1a;将…

c++—引用。。。

目录 目录前言引用的概念交换a和b的值&#xff1a;引用作为函数的返回值常引用例子 前言 纯自学&#xff0c;看的mooc上郭老师的课&#xff0c;整理整理。。。不然全忘了。。 引用的概念 类型名&引用名某变量名&#xff1b; int&rn&#xff1b; r引用了n&#x…

服务器闰秒 linux,闰秒导致部分 Linux 服务器高 CPU 使用率

国际地球自转和参考坐标系统服务(IERS)在2012年6月30日午夜(北京时间7月1号7点59分59秒)增加一闰秒(即出现7&#xff1a;59&#xff1a;60)。由于Linux kernel 2.6.29之前版本存在bug&#xff0c;在进行闰秒调整时可能会引起系统时钟服务ntpd进程死锁。Debian Lenny、RHEL/Cent…

const

目录 目录定义常量定义常量指针定义常引用 定义常量 const int max22&#xff1b; const double p3.1415; const char* sch"zzuli"; 定义常量指针 1.不可通过常量指针修改其指向的内容 &#xff5b;常量指针指向的内容不能随意修改&#xff5d; int n,m; cons…