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中合并两个文本文件并按照姓名首字母排序的例子
Apr 25 Python
Python处理RSS、ATOM模块FEEDPARSER介绍
Feb 18 Python
Python单例模式实例详解
Mar 01 Python
使用Python的turtle模块画图的方法
Nov 15 Python
深入理解Python单元测试unittest的使用示例
Nov 18 Python
Python如何爬取微信公众号文章和评论(基于 Fiddler 抓包分析)
Jun 28 Python
基于Python实现大文件分割和命名脚本过程解析
Sep 29 Python
基于python实现地址和经纬度转换
May 19 Python
Python中socket网络通信是干嘛的
May 27 Python
Python魔术方法专题
Jun 19 Python
大数据分析用java还是Python
Jul 06 Python
python 装饰器重要在哪
Feb 14 Python
python实现简单的名片管理系统
Python实战之实现康威生命游戏
Python 制作自动化翻译工具
教你用Python写一个植物大战僵尸小游戏
python爬取新闻门户网站的示例
Apr 25 #Python
python自然语言处理之字典树知识总结
Python自然语言处理之切分算法详解
Apr 25 #Python
You might like
Discuz Uchome ajaxpost小技巧
2011/01/04 PHP
PHP读取txt文件的内容并赋值给数组的代码
2011/11/03 PHP
php准确计算复活节日期的方法
2015/04/18 PHP
POST一个JSON格式的数据给Restful服务实例详解
2017/04/07 PHP
PHP面向对象五大原则之开放-封闭原则(OCP)详解
2018/04/04 PHP
PHP+MySQL使用mysql_num_rows实现模糊查询图书信息功能
2018/05/31 PHP
如何确保JavaScript的执行顺序 之jQuery.html并非万能钥匙
2011/03/03 Javascript
js常用自定义公共函数汇总
2014/01/15 Javascript
AngularJS入门知识之MVW类框架的编程思想探讨
2014/12/08 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
2016/12/08 Javascript
详解js中常规日期格式处理、月历渲染和倒计时函数
2016/12/28 Javascript
基于AngularJS的简单使用详解
2017/09/10 Javascript
在vue中实现简单页面逆传值的方法
2017/11/27 Javascript
vue 纯js监听滚动条到底部的实例讲解
2018/09/03 Javascript
JavaScript使用ul中li标签实现删除效果
2019/04/15 Javascript
Vue+Express实现登录状态权限验证的示例代码
2019/05/05 Javascript
vue中的面包屑导航组件实例代码
2019/07/01 Javascript
使用jQuery实现掷骰子游戏
2019/10/24 jQuery
如何封装Vue Element的table表格组件
2021/02/06 Vue.js
Django admin实现图书管理系统菜鸟级教程完整实例
2017/12/12 Python
python生成以及打开json、csv和txt文件的实例
2018/11/16 Python
Python包,__init__.py功能与用法分析
2020/01/07 Python
python GUI库图形界面开发之PyQt5结合Qt Designer创建信号与槽的详细方法与实例
2020/03/08 Python
python pandas.DataFrame.loc函数使用详解
2020/03/26 Python
python程序需要编译吗
2020/06/19 Python
python如何运行js语句
2020/09/09 Python
python如何遍历指定路径下所有文件(按按照时间区间检索)
2020/09/14 Python
Python基于argparse与ConfigParser库进行入参解析与ini parser
2021/02/02 Python
Farfetch香港官网:汇集全球时尚奢侈品购物平台
2017/11/26 全球购物
Expedia印度尼西亚站:预订酒店、廉价航班和度假套餐
2018/01/31 全球购物
瑞士最大的图书贸易公司:Orell Füssli
2019/12/28 全球购物
英语专业毕业生自我鉴定
2013/11/09 职场文书
初中英语教学反思
2014/01/25 职场文书
跳蚤市场口号
2014/06/13 职场文书
《攀登者》:“海拔8000米以上,你不能指望任何人”
2019/11/25 职场文书
为什么在foreach循环中JAVA集合不能添加或删除元素
2021/06/11 Java/Android