python如何进行基准测试


Posted in Python onApril 26, 2021

基准测试属于性能测试的一种,用于评估和衡量软件的性能指标。我们可以在软件开发的某个阶段通过基准测试建立一个已知的性能水平,称为"基准线"。当系统的软硬件环境发生变化之后再进行一次基准测试以确定那些变化对性能的影响。 这是基准测试最常见的用途。

Donald Knuth在1974年出版的《Structured Programming with go to Statements》提到:

毫无疑问,对效率的片面追求会导致各种滥用。程序员会浪费大量的时间在非关键程序的速度上,实际上这些尝试提升效率的行为反倒可能产生很大的负面影响,特别是当调试和维护的时候。我们不应该过度纠结于细节的优化,应该说约97%的场景:过早的优化是万恶之源。
当然我们也不应该放弃对那关键3%的优化。一个好的程序员不会因为这个比例小就裹足不前,他们会明智地观察和识别哪些是关键的代码;但是仅当关键代码已经被确认的前提下才会进行优化。对于很多程序员来说,判断哪部分是关键的性能瓶颈,是很容易犯经验上的错误的,因此一般应该借助测量工具来证明。

虽然经常被解读为不需要关心性能,但是的少部分情况下(3%)应该观察和识别关键代码并进行优化。

基准(benchmarking)测试工具

python中提供了非常多的工具来进行基准测试。

为了使演示的例子稍微有趣,我们来随机生成一个列表,并对列表中数字进行排序。

import random


def random_list(start, end, length):
    """
    生成随机列表
    :param start: 随机开始数
    :param end: 随机结束数
    :param length: 列表长度
    """
    data_list = []
    for i in range(length):
        data_list.append(random.randint(start, end))
    return data_list


def bubble_sort(arr):
    """
    冒泡排序: 对列表进行排序
    :param arr 列表
    """
    n = len(arr)
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr


if __name__ == '__main__':
    get_data_list = random_list(1, 99, 10)
    ret = bubble_sort(get_data_list)
    print(ret)

运行结果如下:

❯ python .\demo.py
[8, 16, 22, 31, 42, 58, 66, 71, 73, 91]

timeit

timeit是python自带的模块,用来进行基准测试非常方便。

if __name__ == '__main__':
    import timeit
    get_data_list = random_list(1, 99, 10)
    setup = "from __main__ import bubble_sort"
    t = timeit.timeit(
        stmt="bubble_sort({})".format(get_data_list),
        setup=setup
        )
    print(t)

运行结果:

❯ python .\demo.py
5.4201355

以测试bubble_sort()函数为例。timeit.timeit() 参数说明。

  • stmt:需要测试的函数或语句,字符串形式.
  • setup: 运行的环境,本例子中表示if __name__ == '__main__':.
  • number: 执行的次数,省缺则默认是1000000次。所以你会看到运行bubble_sort() 耗时 5秒多。

pyperf

https://github.com/psf/pyperf

pyperf 的用法与timeit比较类似,但它提供了更丰富结果。(注:我完全是发现了这个库才学习基准测试的)

if __name__ == '__main__':
    get_data_list = random_list(1, 99, 10)

    import pyperf
    setup = "from __main__ import bubble_sort"
    runner = pyperf.Runner()
    runner.timeit(name="bubble sort",
                  stmt="bubble_sort({})".format(get_data_list),
                  setup=setup)

运行结果:

❯ python  .\demo.py -o bench.json
.....................
bubble sort: Mean +- std dev: 5.63 us +- 0.31 us

测试结果会写入bench.json 文件。可以使用pyperf stats命令分析测试结果。

❯ python -m pyperf stats bench.json
Total duration: 15.9 sec
Start date: 2021-04-02 00:17:18
End date: 2021-04-02 00:17:36
Raw value minimum: 162 ms
Raw value maximum: 210 ms

Number of calibration run: 1
Number of run with values: 20
Total number of run: 21

Number of warmup per run: 1
Number of value per run: 3
Loop iterations per value: 2^15
Total number of values: 60

Minimum:         4.94 us
Median +- MAD:   5.63 us +- 0.12 us
Mean +- std dev: 5.63 us +- 0.31 us
Maximum:         6.41 us

  0th percentile: 4.94 us (-12% of the mean) -- minimum
  5th percentile: 5.10 us (-9% of the mean)
 25th percentile: 5.52 us (-2% of the mean) -- Q1
 50th percentile: 5.63 us (+0% of the mean) -- median
 75th percentile: 5.81 us (+3% of the mean) -- Q3
 95th percentile: 5.95 us (+6% of the mean)
100th percentile: 6.41 us (+14% of the mean) -- maximum

Number of outlier (out of 5.07 us..6.25 us): 6

pytest-benchmark

https://github.com/ionelmc/pytest-benchmark

pytest-benchmark是 pytest单元测试框架的一个插件。 单独编写单元测试用例:

from demo import bubble_sort


def test_bubble_sort(benchmark):
    test_list = [5, 2, 4, 1, 3]
    result = benchmark(bubble_sort, test_list)
    assert result == [1, 2, 3, 4, 5]

需要注意:

  • 导入bubble_sort() 函数。
  • benchmark 作为钩子函数使用,不需要导入包。前提是你需要安装pytest和pytest-benchmark。
  • 为了方便断言,我们就把要排序的数固定下来了。

运行测试用例:

❯ pytest -q .\test_demo.py
.                                                                       [100%]

------------------------------------------------ benchmark: 1 tests -----------------------------------------------
Name (time in us)        Min       Max    Mean  StdDev  Median     IQR   Outliers  OPS (Kops/s)  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------
test_bubble_sort      1.6000  483.2000  1.7647  2.6667  1.7000  0.0000  174;36496      566.6715  181819           1
-------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
1 passed in 1.98s

加上 --benchmark-histogram 参数,你会得到一张图表

❯ pytest -q .\test_demo.py --benchmark-histogram
.                                                                                                                [100%]

------------------------------------------------ benchmark: 1 tests -----------------------------------------------
Name (time in us)        Min      Max    Mean  StdDev  Median     IQR    Outliers  OPS (Kops/s)  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------
test_bubble_sort      1.6000  53.9000  1.7333  0.3685  1.7000  0.0000  1640;37296      576.9264  178572           1
-------------------------------------------------------------------------------------------------------------------


Generated histogram: D:\github\test-circle\article\code\benchmark_20210401_165958.svg

图片如下:

python如何进行基准测试

关于基准测试的工具还有很多,这里就不再介绍了。

经过基准测试发现程序变慢了,那么接下来需要做的就是代码性能分析了,我下篇再来介绍。

以上就是python如何进行基准测试的详细内容,更多关于python 基准测试的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python实现代理服务功能实例
Nov 15 Python
Python实现抓取百度搜索结果页的网站标题信息
Jan 22 Python
详解Python中映射类型的内建函数和工厂函数
Aug 19 Python
python实现可以断点续传和并发的ftp程序
Sep 13 Python
python+selenium实现163邮箱自动登陆的方法
Dec 31 Python
python切片及sys.argv[]用法详解
May 25 Python
在IPython中执行Python程序文件的示例
Nov 01 Python
使用Django开发简单接口实现文章增删改查
May 09 Python
python批量修改图片尺寸,并保存指定路径的实现方法
Jul 04 Python
修改Pandas的行或列的名字(重命名)
Dec 18 Python
Pytorch maxpool的ceil_mode用法
Feb 18 Python
pytorch SENet实现案例
Jun 24 Python
python实现简单的名片管理系统
Python实战之实现康威生命游戏
Python 制作自动化翻译工具
教你用Python写一个植物大战僵尸小游戏
python爬取新闻门户网站的示例
Apr 25 #Python
python自然语言处理之字典树知识总结
Python自然语言处理之切分算法详解
Apr 25 #Python
You might like
深入PHP autoload机制的详解
2013/06/09 PHP
php去除头尾空格的2种方法
2015/03/16 PHP
PHP也能干大事 随机函数
2015/04/14 PHP
thinkphp3.x中cookie方法的用法分析
2016/05/19 PHP
基于PHP实现短信验证码接口(容联运通讯)
2016/09/06 PHP
PHP匿名函数(闭包函数)详解
2019/03/22 PHP
Laravel获取当前请求的控制器和方法以及中间件的例子
2019/10/11 PHP
通过Unicode转义序列来加密,按你说的可以算是混淆吧
2007/05/06 Javascript
jquery.Jwin.js 基于jquery的弹出层插件代码
2012/05/23 Javascript
jquery改变tr背景色的示例代码
2013/12/28 Javascript
jQuery根据用户电脑是mac还是pc加载对应样式的方法
2015/06/26 Javascript
vue2.0开发实践总结之入门篇
2016/12/06 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
微信小程序 页面跳转事件绑定的实例详解
2017/09/20 Javascript
基于jQuery实现Ajax验证用户名是否可用实例
2018/03/25 jQuery
关于vue中的ajax请求和axios包问题
2018/04/19 Javascript
koa socket即时通讯的示例代码
2018/09/07 Javascript
vue解决弹出蒙层滑动穿透问题的方法
2018/09/22 Javascript
vue组件之间通信实例总结(点赞功能)
2018/12/05 Javascript
微信小程序MUI侧滑导航菜单示例(Popup弹出式,左侧滑动,右侧不动)
2019/01/23 Javascript
vue2之简易的pc端短信验证码的问题及处理方法
2019/06/03 Javascript
Element-ui DatePicker显示周数的方法示例
2019/07/19 Javascript
jQuery实现移动端图片上传预览组件的方法分析
2020/05/01 jQuery
详解Python中的文本处理
2015/04/11 Python
python使用pil库实现图片合成实例代码
2018/01/20 Python
使用python分析统计自己微信朋友的信息
2019/07/19 Python
Tornado实现多进程/多线程的HTTP服务详解
2019/07/25 Python
python中Django文件上传方法详解
2020/08/05 Python
用python实现一个简单的验证码
2020/12/09 Python
python画图时设置分辨率和画布大小的实现(plt.figure())
2021/01/08 Python
英国领先的酒类网上商城:TheDrinkShop
2017/03/16 全球购物
研究生求职推荐信范文
2013/11/30 职场文书
中学生演讲稿
2014/04/26 职场文书
2015年团队工作总结范文
2015/05/04 职场文书
怒海潜将观后感
2015/06/11 职场文书
中学图书馆工作总结
2015/08/11 职场文书