Python基准测试实战:timeit、pyperf与pytest-benchmark详解

沿途有光
沿途有光
发布时间:2026-10-14 | 4人浏览过
原创

本文深入解析Python中的基准测试方法,涵盖timeit、pyperf及pytest-benchmark三大工具。通过冒泡排序示例,详细演示如何建立性能基准线、分析耗时数据及生成可视化图表,帮助开发者精准定位关键代码瓶颈,避免过早优化陷阱。

基准测试作为性能测试的核心环节,旨在量化评估软件系统的性能指标。在软件开发周期中,通过基准测试可确立初始的“基准线”性能水平。当系统经历软硬件环境变更或代码迭代后,再次执行基准测试即可量化评估这些变更对性能产生的具体影响。这是基准测试最典型的应用场景。

Donald Knuth在1974年出版的著作《Structured Programming with go to Statements》中曾指出:

对效率的片面追求往往导致滥用。程序员可能将大量时间耗费在非关键路径的性能提升上,这些优化尝试有时反而带来显著的负面影响,尤其在代码调试与维护阶段。因此,不应过度纠结于细枝末节的优化,据统计约97%的场景下,“过早优化是万恶之源”。 然而,这并不意味着放弃那关键的3%。优秀的程序员不会因比例微小而止步,他们会通过明智的观察识别关键代码;但前提是必须确认该部分为性能瓶颈。由于判断瓶颈常依赖经验且易出错,通常应借助测量工具进行实证分析。

尽管常被误解为无需关注性能,但在少数(约3%)关键场景下,仍需观察并优化核心代码。

Python基准测试工具概览

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 相关产品和应用

全部下载

专题列表