一个优秀的程序员,在保证业务正常的条件下都会追求自己的程序更快、更省。更快:运行时间短;更省:相对节省计算机资源(比如:CPU、Memory)。一般都是以这两种衡量方式来度量自己的程序及进一步优化自己程序的空间。更专业的性能分析软件一般有两类方法论:event-based profiling和statistical profiling 。
并不是所有编程语言都支持这类性能分析,支持这类分析的语言主要有:
基于事件的性能分析(event-based profiler or tracing profiler)是通过手机程序执行过程中的具体事件进行工作的,这些性能分析会产生大量的数据,基本而言,你监听的事件越多产生的数据量句越多。这导致它们不太实用,在开始对程序进行性能往往不是首选,当其他性能分析不够用或者不精准它们可以作为最后的选择。我们看一下一个python的例子:
以固定的事件间隔对程序计数器进行抽样统计,可以查看每个函数的消耗时间。由于它对程序计数器进行抽样,所以数据结果是对真实值的统计近似。以便于查看分析程序的性能细节,查出性能瓶颈。
现在我们来谈谈Python的性能分析,Python性能分析有很多工具和模块。比如:time粗粒度分析、cProfile,line_Profile等等。
time.time()简单的衡量运行时间,我们看一下Demo:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
class Timer(object):
def __init__(self):
pass
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
self.end = time.time()
self.secs = self.end - self.start
print 'costed time: %f ms' % (self.secs * 1000)
def test():
k = []
for i in range(1000000):
k.append(i**2+1000)
return k
if __name__ == "__main__":
with Timer() as t:
test()
#运行结果:
costed time: 776.966095 ms
将要测量时间的代码用Python关键字with和Timer上下文管理器包起来。它会在你的代码运行的时候开始计时,并且在执行结束的完成计时。
cProfile是Python默认的性能分析器,它是一种确定性的性能分析器,提供了一组API来帮助开发者手机Python程序运行的信息。统计每个函数消耗的CPU时间,它只测量CPU时间,并不关心内存消耗和其他内存相关信息统计。
import cProfile
import pstats
def get_result():
sum = 0
for i in range(10000):
sum += add_result(i,i+1)
return sum
def add_result(a,b):
return a+b
if __name__ == "__main__":
cProfile.run("get_result()")
#结果如下:
10004 function calls in 0.018 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.018 0.018 <string>:1(<module>)
10000 0.006 0.000 0.006 0.000 untitled-1.py:10(add_result)
1 0.011 0.011 0.018 0.018 untitled-1.py:4(get_result)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {range}
1004代表一共函数调用,花费了0.018秒,第一列ncalls代表了函数总共调用次数,第二列tottime总共运行时间,它不包括内部其它函数运行的时间,第三列cumtime函数总计运行时间,含调用的函数运行时间,tottime和cumtime是不一样的。可以这样理解:get_result花费时间等于tottime(get_result)+cumtime(add_result)最后一列比显示调用函数名。这是最常用的用法,cprofile也提供很多API,比如:查看函数调用了那些函数等等。
这个是耕细粒度的性能分析,这个分析一行一行函数分析,不过得需要装饰器注册@profile然后还得需要kernprof脚本将会在执行的时候将它自动地注入到你的脚步的运行时。下面我们来看一下例子:
import cProfile
import pstats
@profile
def get_result():
sum = 0
for i in range(10000):
sum += add_result(i,i+1)
return sum
def add_result(a,b):
return a+b
if __name__ == "__main__":
get_result()
我们需要通过kernprof运行这个脚本,如下所示:
kernprof -l -v untitled-1.py
-l选项通知kernprof注入@profile装饰器到你的脚步的内建函数,-v选项通知kernprof在脚本执行完毕的时候显示计时信息。分析如下所示:
rote profile results to untitled-1.py.lprof
Timer unit: 1e-06 s
Total time: 0.008289 s
File: untitled-1.py
Function: get_result at line 4
Line # Hits Time Per Hit % Time Line Contents
==============================================================
4 @profile
5 def get_result():
6 1 2 2.0 0.0 sum = 0
7 10001 2854 0.3 34.4 for i in range(10000):
8 10000 5433 0.5 65.5 sum += add_result(i,i+1)
9 1 0 0.0 0.0 return sum
这个很好理解,无需解释了。在下一个篇博客中,分析Python内存使用和如何查找内存溢出。