性能分析简介
主流的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))

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、数据可视化 如果在错误发生之前,你不清楚自己要找的问题,只想知道优化代码的方式,那么洞察你已经预处理过的数据的最好方式就是数据可视化。
计算机很酣畅处理数据,但是人类更善于通过图形来发现模式和理解现有信息中的某种特征。 例子: 通过可视化图形,显示出客户集中访问的时间,我们可以在高峰时间为基础设施增加更多资源。