Python 性能分析工具简介
Table of Contents
性能分析和调优工具简介
总会遇到一个时候你会想提高程序执行效率,想看看哪部分耗时长成为瓶颈,想知道程序运行时内存和CPU使用情况。这时候你会需要一些方法对程序进行性能分析和调优。
Context Manager
可以上下文管理器自己实现一个计时器, 参见之前的介绍 timeit 文章里做的那样,通过定义类的 __enter__ 和 __exit__ 方法来实现对管理的函数计时, 类似如:
# 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 # 毫秒
if self.verbose:
print 'elapsed time: %f ms' % self.msecs
使用方式如下:
from timer import Timer
with Timer() as t:
foo()
print "=> foo() spends %s s" % t.secs
Decorator
然而我认为装饰器的方式更加优雅
import time
from functools import wraps
def timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
t0 = time.time()
result = function(*args, **kwargs)
t1 = time.time()
print ("Total time running %s: %s seconds" %
(function.func_name, str(t1-t0))
)
return result
return function_timer
使用就很简单了:
@timer
def my_sum(n):
return sum([i for i in range(n)])
if __name__ == "__main__":
my_sum(10000000)
运行结果:
➜ python profile.py
Total time running my_sum: 0.817697048187 seconds
系统自带的time命令
使用示例如下:
➜ time python profile.py
Total time running my_sum: 0.854454040527 seconds
python profile.py 0.79s user 0.18s system 98% cpu 0.977 total
上面的结果说明: 执行脚本消耗0.79sCPU时间, 0.18秒执行内核函数消耗的时间,总共0.977s时间。
其中, total时间 - (user时间 + system时间) = 消耗在输入输出和系统执行其它任务消耗的时间
python timeit 模块
可以用来做benchmark, 可以方便的重复一个程序执行的次数,来查看程序可以运行多块。具体参考之前写的文章。
cProfile
直接看带注释的使用示例吧。
#coding=utf8
def sum_num(max_num):
total = 0
for i in range(max_num):
total += i
return total
def test():
total = 0
for i in range(40000):
total += i
t1 = sum_num(100000)
t2 = sum_num(200000)
t3 = sum_num(300000)
t4 = sum_num(400000)
t5 = sum_num(500000)
test2()
return total
def test2():
total = 0
for i in range(40000):
total += i
t6 = sum_num(600000)
t7 = sum_num(700000)
return total
if __name__ == "__main__":
import cProfile
# # 直接把分析结果打印到控制台
# cProfile.run("test()")
# # 把分析结果保存到文件中
# cProfile.run("test()", filename="result.out")
# 增加排序方式
cProfile.run("test()", filename="result.out", sort="cumulative")
cProfile将分析的结果保存到result.out文件中,但是以二进制形式存储的,想直接查看的话用提供的 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")
截取一个查看test()调用了哪些函数的输出示例:
➜ python python profile.py
Random listing order was used
List reduced from 6 to 2 due to restriction <'test'>
Function called...
ncalls tottime cumtime
profile.py:24(test2) -> 2 0.061 0.077 profile.py:3(sum_num)
1 0.000 0.000 {range}
profile.py:10(test) -> 5 0.073 0.094 profile.py:3(sum_num)
1 0.002 0.079 profile.py:24(test2)
1 0.001 0.001 {range}
profile.Profile
cProfile还提供了可以自定义的类,可以更精细的分析, 具体看文档。
格式如: class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)
下面这个例子来自官方文档:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
pr.disable()
s = StringIO.StringIO()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
lineprofiler
lineprofiler是一个对函数进行逐行性能分析的工具,可以参见github项目说明,地址: https://github.com/rkern/line_profiler
示例
#coding=utf8
def sum_num(max_num):
total = 0
for i in range(max_num):
total += i
return total
@profile # 添加@profile 来标注分析哪个函数
def test():
total = 0
for i in range(40000):
total += i
t1 = sum_num(10000000)
t2 = sum_num(200000)
t3 = sum_num(300000)
t4 = sum_num(400000)
t5 = sum_num(500000)
test2()
return total
def test2():
total = 0
for i in range(40000):
total += i
t6 = sum_num(600000)
t7 = sum_num(700000)
return total
test()
通过 kernprof 命令来注入分析,运行结果如下:
➜ kernprof -l -v profile.py
Wrote profile results to profile.py.lprof
Timer unit: 1e-06 s
Total time: 3.80125 s
File: profile.py
Function: test at line 10
Line # Hits Time Per Hit % Time Line Contents
==============================================================
10 @profile
11 def test():
12 1 5 5.0 0.0 total = 0
13 40001 19511 0.5 0.5 for i in range(40000):
14 40000 19066 0.5 0.5 total += i
15
16 1 2974373 2974373.0 78.2 t1 = sum_num(10000000)
17 1 58702 58702.0 1.5 t2 = sum_num(200000)
18 1 81170 81170.0 2.1 t3 = sum_num(300000)
19 1 114901 114901.0 3.0 t4 = sum_num(400000)
20 1 155261 155261.0 4.1 t5 = sum_num(500000)
21 1 378257 378257.0 10.0 test2()
22
23 1 2 2.0 0.0 return total
hits(执行次数) 和 time(耗时) 值高的地方是有比较大优化空间的地方。
memoryprofiler
类似于"lineprofiler"对基于行分析程序内存使用情况的模块。github 地址:https://github.com/fabianp/memory_profiler 。ps:安装 psutil, 会分析的更快。
同样是上面"lineprofiler"中的代码,运行 python -m memory_profiler profile.py 命令生成结果如下:
➜ python -m memory_profiler profile.py
Filename: profile.py
Line # Mem usage Increment Line Contents
================================================
10 24.473 MiB 0.000 MiB @profile
11 def test():
12 24.473 MiB 0.000 MiB total = 0
13 25.719 MiB 1.246 MiB for i in range(40000):
14 25.719 MiB 0.000 MiB total += i
15
16 335.594 MiB 309.875 MiB t1 = sum_num(10000000)
17 337.121 MiB 1.527 MiB t2 = sum_num(200000)
18 339.410 MiB 2.289 MiB t3 = sum_num(300000)
19 342.465 MiB 3.055 MiB t4 = sum_num(400000)
20 346.281 MiB 3.816 MiB t5 = sum_num(500000)
21 356.203 MiB 9.922 MiB test2()
22
23 356.203 MiB 0.000 MiB return total
TODO objgraph
参考资料:
- https://docs.python.org/2/library/profile.html#module-cProfile
- http://xianglong.me/article/analysis-python-application-performance-using-cProfile/
- http://www.cnblogs.com/btchenguang/archive/2012/02/03/2337112.html
- https://www.huyng.com/posts/python-performance-analysis
- http://www.marinamele.com/7-tips-to-time-python-scripts-and-control-memory-and-cpu-usage
Python 性能分析工具简介的更多相关文章
- Python性能分析工具Profile
Python性能分析工具Profile 代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,对于比较复杂的代码可以借助一些工具来定位,python 内置了丰富的性能分析工具,如 ...
- Python性能分析工具
import cProfile import pstats from flask import Flask,jsonify, request @app.route("/test", ...
- cProfile——Python性能分析工具
Python自带了几个性能分析的模块:profile.cProfile和hotshot,使用方法基本都差不多,无非模块是纯Python还是用C写的.本文介绍cProfile. 例子 import t ...
- Python性能分析
Python性能分析 https://www.cnblogs.com/lrysjtu/p/5651816.html https://www.cnblogs.com/cbscan/articles/33 ...
- 系统级性能分析工具perf的介绍与使用
测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...
- Linux性能分析工具与图形化方法
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~. 作者:赵坤|腾讯魔王工作室后台开发工程师 在项目开发中,经常会遇到程序启动时间过长.CPU使用率过高等问题,这个时候需要依靠性能分析工具来 ...
- 系统级性能分析工具perf的介绍与使用[转]
测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...
- Python性能分析与优化PDF高清完整版免费下载|百度云盘
百度云盘|Python性能分析与优化PDF高清完整版免费下载 提取码:ubjt 内容简介 全面掌握Python代码性能分析和优化方法,消除性能瓶颈,迅速改善程序性能! 对于Python程序员来说,仅仅 ...
- 如何进行python性能分析?
在分析python代码性能瓶颈,但又不想修改源代码的时候,ipython shell以及第三方库提供了很多扩展工具,可以不用在代码里面加上统计性能的装饰器,也能很方便直观的分析代码性能.下面以我自己实 ...
随机推荐
- cf1042F. Leaf Sets(贪心)
题意 题目链接 给出一棵树,删除一些边,使得任意联通块内的任意点距离不超过$k$ sol 考场上想的贪心是对的:考虑一棵子树,如果该子树内最深的两个节点的距离相加$>k$就删掉最深的那个点,向上 ...
- bootstrapValidator 重置表单
最近在公司做业务系统后台,用的js框架还是jquery ui框架 是以bootstrap为基础的beyondadmin-v1.4.s3这套,用起来还挺不错,所以公司所有的后台ui都使用这套.这套ui ...
- css最佳实践(reset.css)
html, body, div, span, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,abbr, address, cite ...
- 703. 数据流中的第 K 大元素
设计一个找到数据流中第 K 大元素的类(class).注意是排序后的第 K 大元素,不是第 K 个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组 nums 的构造器, ...
- DataGridView控件使用大全
转自:http://www.cnblogs.com/xiaofengfeng/archive/2011/04/16/2018504.html DataGridView控件 DataGridView是用 ...
- hihoCoder #1044 : 状态压缩·一 (清垃圾)
题意: 某车厢有一列座位,共有n个位置,清洁工要在这n个位置上清垃圾,但是不能全部位置都清理,只能选择部分.选择的规则是,连续的m个位置内,不能够清理超过q个,也就是说从第1~m个位置最多可以清q个, ...
- 系统装更新补丁出现“正在此计算机上搜索更新”,有时等待N长时间也没有反应
系统装更新补丁出现“正在此计算机上搜索更新”,有时等待N长时间也没有反应 管理员身份运行 net stop wuauserv net stop CryptSvc ren %windir%\system ...
- JIRA Plugin Development——Configurable Custom Field Plugin
关于JIRA Plugin开发的中文资料相当少,这可能还是由于JIRA Plugin开发在国内比较小众的原因吧,下面介绍下自己的一个JIRA Plugin开发的详细过程. 业务需求 创建JIRA IS ...
- POJ 3046 Ant Counting(递推,和号优化)
计数类的问题,要求不重复,把每种物品单独考虑. 将和号递推可以把转移优化O(1). f[i = 第i种物品][j = 总数量为j] = 方案数 f[i][j] = sigma{f[i-1][j-k], ...
- 分析ELF的加载过程
http://blog.chinaunix.net/uid-72446-id-2060538.html 对于可执行文件来说,段的加载位置是固定的,程序段表中如实反映了段的加载地址.对于共享库来?段的加 ...