python如何进行基准测试

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

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

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

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

基准(benchmarking)测试工具

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

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)

运行结果如下:

1

2

❯ python .\demo.py

[8, 16, 22, 31, 42, 58, 66, 71, 73, 91]

timeit

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

1

2

3

4

5

6

7

8

9

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)

运行结果:

1

2

❯ 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比较类似,但它提供了更丰富结果。(注:我完全是发现了这个库才学习基准测试的)

1

2

3

4

5

6

7

8

9

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)

运行结果:

1

2

3

❯ python  .\demo.py -o bench.json

.....................

bubble sort: Mean +- std dev: 5.63 us +- 0.31 us

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

❯ 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单元测试框架的一个插件。 单独编写单元测试用例:

1

2

3

4

5

6

7

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。
  • 为了方便断言,我们就把要排序的数固定下来了。

运行测试用例:

1

2

3

4

5

6

7

8

9

10

11

12

13

❯ 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 参数,你会得到一张图表

1

2

3

4

5

6

7

8

9

10

11

❯ 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

图片如下:

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

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

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值