当自动化测试的量特别大的时候,python性能就显得尤为重要。 往往高手和菜鸟的区别在性能上体现出来了。
菜鸟往往能够简单的实现功能,不停地加case,只要能达到目的,完成任务就行了。
高手往往能够看出当前架构的劣势,并不断完善框架,优化性能,以达到最好的效果。
我所知道的一个项目,API自动化100来个case. 业务场景也不复杂,就是对一些API返回做一些数据上的 smoke验证。 你猜它的代价是多大。 两个人花一年全职来写并维护,跑起来需要2小时。抛开接口反应时间不说,我看了代码,有很多地方可以优化的点。(对于这个结果,我这里只能呵呵了,贵公司真有钱!)
我在网上找了一些python性能优化的资料,总结如下:
1.timeit:
代码语言:javascript复制import timeit
def fun():
for i in range(100000):
a = i * i
timeit.timeit('fun()', 'from __main__ import fun', number=1)
0.02922706632834235
timeit只输出被测试代码的总运行时间,单位为秒,没有详细的统计。
2.profile
profile:纯Python实现的性能测试模块,接口和cProfile一样。
代码语言:javascript复制 def fun():
for i in range(100000):
a = i * i
profile.run('fun()')
5 function calls in 0.031 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.016 0.016 :0(exec)
1 0.016 0.016 0.016 0.016 :0(setprofile)
1 0.016 0.016 0.016 0.016 <pyshell#13>:1(fun)
1 0.000 0.000 0.016 0.016 <string>:1(<module>)
1 0.000 0.000 0.031 0.031 profile:0(fun())
0 0.000 0.000 profile:0(profiler)
ncall:函数运行次数
tottime:函数的总的运行时间,减去函数中调用子函数的运行时间
第一个percall:percall = tottime / nclall
cumtime:函数及其所有子函数调整的运行时间,也就是函数开始调用到结束的时间。
第二个percall:percall = cumtime / nclall
3.cProfile
profile:c语言实现的性能测试模块,接口和profile一样。
代码语言:javascript复制import cProfile
def fun():
for i in range(100000):
a = i * i
cProfile.run('fun()')
4 function calls in 0.024 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.024 0.024 0.024 0.024 <pyshell#17>:1(fun)
1 0.000 0.000 0.024 0.024 <string>:1(<module>)
1 0.000 0.000 0.024 0.024 {built-in method exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
ncalls、tottime、percall、cumtime含义同profile。
4.line_profiler
安装:
代码语言:javascript复制pip install line_profiler
安装之后kernprof.py会加到环境变量中。
line_profiler可以统计每行代码的执行次数和执行时间等,时间单位为微秒。
测试代码:
C:Python34test.py
代码语言:javascript复制
@profile
def fun():
a = 0
b = 0
for i in range(100000):
a = a i * i
for i in range(3):
b = 1
time.sleep(0.1)
return a b
fun()
使用:
1.在需要测试的函数加上@profile装饰,这里我们把测试代码写在C:Python34test.py文件上.
2.运行命令行:kernprof -l -v C:Python34test.py
输出结果如下:
Total Time:测试代码的总运行时间 Hits:表示每行代码运行的次数 Time:每行代码运行的总时间 Per Hits:每行代码运行一次的时间 % Time:每行代码运行时间的百分比
5.memory_profiler:
memory_profiler工具可以统计每行代码占用的内存大小。
安装:
代码语言:javascript复制pip install memory_profiler
pip install psutil
测试代码:
同line_profiler。
使用:
1.在需要测试的函数加上@profile装饰
2.执行命令:python -m memory_profiler C:Python34test.py
输出如下:
6.PyCharm图形化性能测试工具:
PyCharm提供了图像化的性能分析工具,使用方法利用PyCharm的Profile工具进行Python性能分析。
PyCharm提供了性能分析工具Run-》Profile,如下图所示。利用Profile工具可以对代码进行性能分析,找出瓶颈所在。
测试:
下面以一段测试代码来说明如何使用pycharm的Profile功能。
测试代码见下文,文件命名为Test.py, 一共有5个函数,每个函数都调用了time.sleep进行延时,其中fun5函数调用了fun4函数:
代码语言:javascript复制import time
def fun1(a, b):
print('fun1')
print(a, b)
time.sleep(1)
def fun2():
print('fun2')
time.sleep(1)
def fun3():
print('fun3')
time.sleep(2)
def fun4():
print('fun4')
time.sleep(1)
def fun5():
print('fun5')
time.sleep(1)
fun4()
fun1('foo', 'bar')
fun2()
fun3()
fun5()
点击Run-》Profile开始测试,代码运行结束后会生成一栏测试结果,测试结果由两部分构成,Statistcs(性能统计)和Call Graph(调用关系图):
image
Statistcs(性能统计):
性能统计界面由Name、Call Count、Time(ms)、Own Time(ms) 4列组成一个表格,见下图。
1. 表头Name显示被调用的模块或者函数;Call Count显示被调用的次数;Time(ms)显示运行时间和时间百分比,时间单位为毫秒(ms)。
2.点击表头上的小三角可以升序或降序排列表格。
3.在Name这一个列中双击某一行可以跳转到对应的代码。
4.以fun4这一行举例:fun4被调用了一次,运行时间为1000ms,占整个运行时间的16.7%
image
Call Graph(调用关系图):
Call Graph(调用关系图)界面直观展示了各函数直接的调用关系、运行时间和时间百分比,见下图。
0.右上角的4个按钮表示放大、缩小、真实大小、合适大小;
1.箭头表示调用关系,由调用者指向被调用者;
2.矩形的左上角显示模块或者函数的名称,右上角显示被调用的次数;
3.矩形中间显示运行时间和时间百分比;
4.矩形的颜色表示运行时间或者时间百分比大小的趋势:红色 > 黄绿色 > 绿色,由图可以看出fun3的矩形为黄绿色,fun1为绿色,所有fun3运行时间比fun1长。
5.从图中可以看出Test.py直接调用了fun3、fun1、fun2和fun5函数;fun5函数直接调用了fun4函数;fun1、fun2、fun3、fun4和fun5都直接调用了print以及sleep函数;整个测试代码运行的总时间为6006ms,其中fun3的运行时间为1999ms,所占的时间百分比为33.3%,也就是 1999ms / 6006ms = 33.3%。
对于性能测试,我们需要知道时间都去哪儿了。找出耗时间的地方,做进一步的优化。
以上列举了这么多性能优化的方法,哪种才适合我呢? 对于我个人来说,我不想在原有的方法里面加代码,一来麻烦,二来破坏代码的完整性。 然后希望有完整的时间消耗明细。
个人觉得pycharm的Profile功能很适合我。不管我时候用没有用测试框架,都能直接看出各个地方的消耗时间。