性能分析简介

 

主流的Python性能分析工具,
包括cProfile性能分析器、
line_profiler+kernprof性能分析工具、
KCacheGrind+pyprof2calltree、
RunSnakeRun可视化性能分析工具,
帮助发现程序的性能瓶颈。

性能分析

性能分析是测量程序所使用的资源的。虽然资源正变得越来越便宜。
一旦用户激增,程序通常会崩溃,或者变得异常缓慢。(这显然是由于糟糕的程序设计和缺乏扩展性的架构所造成的。
毕竟一台服务器有限的内存和CPU资源也可能会成为软件的瓶颈。另外就是没做过压力测试)
性能分析:    
    1、运行时间
    2、运行瓶颈:
        沉重的IO操作
        内存泄露
        未经优化的代码被频繁使用
        密集的操作在可以缓存时没有缓存,占用了大量资源。
        
注:I/O关联的代码(文件读/写,数据库查询等)很难有话,因为优化可能会改变程序执行I/O操作的方式(通常是语言的核心操作I/O)。
    相反,优化计算关联的代码(比如程序使用的算法很糟糕),改善性能会比较容易(并一定很简单)。这是因为优化计算关联的代码就是改写程序。 在性能优化接近尾声的时候,剩下的大多数性能瓶颈都是由I
/O关联的代码造成的。

 

 

 

没有优化过的程序通常会在某些子程序上消耗大部分的CPU指令周期。性能分析就是分析代码和它正在使用的资源之间有着怎样的关系。
(占用了多少CPU时间,或者整个程序消耗了多少内存) 性能分析可以帮助开发者深刻地了解程序是如何使用计算机资源的(细致到一个函数被调用了多少次)
过早优化的风险:如果过早优化,结果可能会和原来的代码截然不同。他可能只是完整解决方案的一部分,还可能包含因优化驱动的涉及决策而导致的错误。

性能分析软件有两类方法论

基于事件的性能分析
    通过手机程序执行过程中的具体时间进行工作的。会产生大量数据。
统计式性能分析
基于事件的性能分析
import profile
import sys

def profiler(frame, event, arg):
    print ('PROFILER: %r %r' % (event, arg))

sys.setprofile(profiler)

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

def fib_seq(n):
    seq = [ ]
    if n > 0:
        seq.extend(fib_seq(n-1))
    seq.append(fib(n))
    return seq

print(fib_seq(2))
fib_seq.py
C:\Python35\python.exe "H:/性能分析/B02088_01_01.py"
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'return' 0
PROFILER: 'c_call' <built-in method append of list object at 0x00000000005D7E08>
PROFILER: 'c_return' <built-in method append of list object at 0x00000000005D7E08>
PROFILER: 'return' [0]
PROFILER: 'c_call' <built-in method extend of list object at 0x00000000005D7F08>
PROFILER: 'c_return' <built-in method extend of list object at 0x00000000005D7F08>
PROFILER: 'call' None
PROFILER: 'return' 1
PROFILER: 'c_call' <built-in method append of list object at 0x00000000005D7F08>
PROFILER: 'c_return' <built-in method append of list object at 0x00000000005D7F08>
PROFILER: 'return' [0, 1]
PROFILER: 'c_call' <built-in method extend of list object at 0x00000000005E48C8>
PROFILER: 'c_return' <built-in method extend of list object at 0x00000000005E48C8>
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'return' 1
PROFILER: 'call' None
PROFILER: 'return' 0
PROFILER: 'return' 1
PROFILER: 'c_call' <built-in method append of list object at 0x00000000005E48C8>
PROFILER: 'c_return' <built-in method append of list object at 0x00000000005E48C8>
PROFILER: 'return' [0, 1, 1]
PROFILER: 'c_call' <built-in function print>
[0, 1, 1]
PROFILER: 'c_return' <built-in function print>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method locked of _thread.lock object at 0x000000000114C170>
PROFILER: 'c_return' <built-in method locked of _thread.lock object at 0x000000000114C170>
PROFILER: 'c_call' <built-in method release of _thread.lock object at 0x000000000114C170>
PROFILER: 'c_return' <built-in method release of _thread.lock object at 0x000000000114C170>
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method locked of _thread.lock object at 0x000000000114C170>
PROFILER: 'c_return' <built-in method locked of _thread.lock object at 0x000000000114C170>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method values of dict object at 0x00000000011345C8>
PROFILER: 'c_return' <built-in method values of dict object at 0x00000000011345C8>
PROFILER: 'c_call' <built-in method values of dict object at 0x0000000001138188>
PROFILER: 'c_return' <built-in method values of dict object at 0x0000000001138188>
PROFILER: 'return' [<_MainThread(MainThread, stopped 12524)>]
PROFILER: 'call' None
PROFILER: 'return' False
PROFILER: 'call' None
PROFILER: 'return' False
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in function get_ident>
PROFILER: 'c_return' <built-in function get_ident>
PROFILER: 'return' None
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method acquire of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'c_return' <built-in method acquire of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method acquire of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'c_return' <built-in method acquire of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'return' <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
PROFILER: 'call' None
PROFILER: 'return' <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
PROFILER: 'c_call' <built-in function hasattr>
PROFILER: 'c_return' <built-in function hasattr>
PROFILER: 'call' None
PROFILER: 'return' <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
PROFILER: 'c_call' <built-in method flush of _io.TextIOWrapper object at 0x000000000054E708>
PROFILER: 'c_return' <built-in method flush of _io.TextIOWrapper object at 0x000000000054E708>
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method release of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'c_return' <built-in method release of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'return' None
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method acquire of _thread.RLock object at 0x000000000111F378>
PROFILER: 'c_return' <built-in method acquire of _thread.RLock object at 0x000000000111F378>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method release of _thread.RLock object at 0x000000000111F378>
PROFILER: 'c_return' <built-in method release of _thread.RLock object at 0x000000000111F378>
PROFILER: 'return' None
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method release of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'c_return' <built-in method release of _thread.RLock object at 0x000000000111F3A0>
PROFILER: 'return' None
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method discard of set object at 0x0000000000D2E588>
PROFILER: 'c_return' <built-in method discard of set object at 0x0000000000D2E588>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method discard of set object at 0x0000000000D27BA8>
PROFILER: 'c_return' <built-in method discard of set object at 0x0000000000D27BA8>
PROFILER: 'return' None
PROFILER: 'call' None
PROFILER: 'c_call' <built-in method discard of set object at 0x00000000010DA9E8>
PROFILER: 'c_return' <built-in method discard of set object at 0x00000000010DA9E8>
PROFILER: 'return' None
输出结果
统计式性能分析
优点:
  1、分析的数据更少:由于我们只对程序执行过程进行抽样,而不用保留每一条数据,因此需要分析的信息量会显著减少。
  2、对性能造成的影响更小,使用抽样的方式(系统中断),目标的程序的性能遭受的干扰更小;比上一种方式更小。

 

 

运行时间复杂度:
O(1)
    判断一个数是奇数还是偶数
    用标准输出方式打印信息
O(n)
    查找无序表中的最小元素
    比较两个字符串
    删除链表中的最后一项
O(logn)
    二分查找
    计算斐波那契数列(用矩阵乘法)
O(nlogn)    
    归并排序
    堆排序
    快速排序
O(n2)
    冒泡排序
    遍历二维数组
    插入排序
O(n!)
    暴力破解搜索方法

效率:
    对数>线性>线性对数>平方>阶乘

 

性能分析实践

1、建立回归测试套件
        尤其是面对大型项目时,确保代码具有足够的覆盖率。可以保证你在代码中尝试优化时,不用担心代码结构被破坏。
2、思考代码结构
    
3、耐心
4、尽可能多的收集数据
    系统日志,自定义日志,系统资源快照
5、数据预处理
    当拥有了性能分析器的信息、日志和其他资源之后,在分析之前可能需要对数据进行预处理。不要因为性能分析器不能理解就会比非结构化数据。
   数据分析会往往从其他数据中受益。
6、数据可视化 如果在错误发生之前,你不清楚自己要找的问题,只想知道优化代码的方式,那么洞察你已经预处理过的数据的最好方式就是数据可视化。
计算机很酣畅处理数据,但是人类更善于通过图形来发现模式和理解现有信息中的某种特征。 例子: 通过可视化图形,显示出客户集中访问的时间,我们可以在高峰时间为基础设施增加更多资源。

 

 

 

posted @ 2018-12-28 13:17  慕沁  阅读(615)  评论(0)    收藏  举报