全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-19 8 分钟 ✍️ juanwangdev

Python性能基准测试

建立性能基准体系是优化工作的基础,确保优化有效且可持续。

timeit模块

基本使用

Python
import timeit

# 测试单个表达式
time = timeit.timeit('sum(range(1000))', number=10000)
print(f"Average: {time / 10000 * 1000:.3f} ms per run")

# 测试函数
def test_func():
    return [i**2 for i in range(1000)]

time = timeit.timeit(test_func, number=1000)
print(f"Total: {time:.3f} s for 1000 runs")

# 使用setup导入模块
time = timeit.timeit(
    'random.randint(1, 100)',
    setup='import random',
    number=10000
)

repeat多次测量

Python
import timeit

# 多次测量取最优
times = timeit.repeat(
    'sum(range(10000))',
    number=1000,
    repeat=5  # 重复5次
)

print(f"Best: {min(times):.3f} s")
print(f"All: {times}")

命令行使用

Bash
# 测试代码片段
python -m timeit "sum(range(1000))"

# 指定循环次数和重复次数
python -m timeit -n 1000 -r 5 "sum(range(1000))"

# 输出:
# 1000 loops, best of 5: 27.2 usec per loop

Timer类高级用法

Python
import timeit

# 创建Timer对象
timer = timeit.Timer(
    stmt='sorted(data)',
    setup='data = list(range(1000, 0, -1))'
)

# 自动确定次数
times = timer.autorange()  # 返回(number, time)
print(f"Auto: {times[1] / times[0] * 1000:.3f} ms per loop")

# 多次测量
results = timer.repeat(repeat=10, number=1000)
print(f"Min: {min(results):.3f} s")

pytest-benchmark

安装

Bash
pip install pytest-benchmark

基本测试

Python
# test_performance.py

def test_sum(benchmark):
    # benchmark自动测量函数性能
    result = benchmark(sum, range(1000))
    assert result == 499500

def test_list_comprehension(benchmark):
    result = benchmark(lambda: [i**2 for i in range(1000)])
    assert len(result) == 1000

运行测试

Bash
pytest test_performance.py --benchmark-only

# 输出示例:
# Name (time in ms)          Min      Max     Mean    StdDev
# ---------------------------------------------------------
# test_sum                0.0272   0.0350   0.0289   0.0020
# test_list_comprehension 0.1100   0.1250   0.1150   0.0050

参数化测试

Python
import pytest

@pytest.mark.parametrize("size", [100, 1000, 10000])
def test_sort(benchmark, size):
    data = list(range(size, 0, -1))
    result = benchmark(sorted, data)
    assert result == list(range(size))

对比测试

Python
def test_append_vs_extend(benchmark):
    # 测试append
    benchmark(lambda: [x for x in range(1000)])

def test_extend(benchmark):
    # 测试extend
    benchmark(lambda: list(range(1000)))

# pytest会自动对比两个函数的性能

保存基准结果

Bash
# 保存基准结果
pytest test_performance.py --benchmark-save=baseline

# 对比基准
pytest test_performance.py --benchmark-compare=baseline

cProfile性能分析

基本使用

Python
import cProfile

def target_function():
    total = 0
    for i in range(100000):
        total += i ** 2
    return total

# 分析函数
cProfile.run('target_function()')

# 输出:
#          5 function calls in 0.015 seconds
#    Ordered by: standard name
#
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         1    0.015    0.015    0.015    0.015 test.py:2(target_function)

分析脚本

Bash
python -m cProfile script.py

# 按时间排序
python -m cProfile -s cumtime script.py

# 保存结果
python -m cProfile -o output.prof script.py

使用pstats分析

Python
import cProfile
import pstats

# 生成profile
cProfile.run('target_function()', 'output.prof')

# 分析结果
stats = pstats.Stats('output.prof')

# 按累计时间排序
stats.sort_stats('cumtime')
stats.print_stats(10)  # 显示前10

# 按调用次数排序
stats.sort_stats('ncalls')
stats.print_stats(10)

# 查看特定函数的调用者
stats.print_callers('target_function')

# 查看特定函数调用的函数
stats.print_callees('target_function')

性能测试最佳实践

稳定的测试环境

Python
import timeit
import gc

# 禁用GC减少干扰
gc.disable()
try:
    time = timeit.timeit('sum(range(1000))', number=10000)
finally:
    gc.enable()

# 多次预热
for _ in range(3):
    test_func()  # 预热,让系统稳定

# 正式测量
time = timeit.timeit(test_func, number=1000)

消除干扰因素

Python
import time
import sys

# 使用min避免系统干扰
times = []
for _ in range(10):
    start = time.perf_counter()
    test_func()
    end = time.perf_counter()
    times.append(end - start)

print(f"Best time: {min(times) * 1000:.3f} ms")

# 使用perf_counter而非time.time(更高精度)

测试不同参数范围

Python
import timeit

def test_range(start, end, step):
    stmt = f'sum(range({start}, {end}, {step}))'
    time = timeit.timeit(stmt, number=10000)
    return time

# 测试不同范围
results = []
for n in [100, 1000, 10000, 100000]:
    time = test_range(0, n, 1)
    results.append((n, time))

for n, t in results:
    print(f"n={n}: {t:.3f} s")

建立基准体系

基准测试类

Python
import timeit
import json
from pathlib import Path

class PerformanceBenchmark:
    def __init__(self, name):
        self.name = name
        self.results = {}
        self.baseline_file = Path(f"baseline_{name}.json")

    def add_test(self, test_name, stmt, setup='', number=1000):
        "添加测试"
        times = timeit.repeat(stmt, setup, number=number, repeat=5)
        self.results[test_name] = {
            'min': min(times),
            'mean': sum(times) / len(times),
            'times': times,
            'number': number
        }

    def save_baseline(self):
        "保存基准"
        with open(self.baseline_file, 'w') as f:
            json.dump(self.results, f)

    def compare_baseline(self):
        "对比基准"
        if not self.baseline_file.exists():
            print("No baseline found")
            return

        baseline = json.load(open(self.baseline_file))
        for name, current in self.results.items():
            base = baseline.get(name)
            if base:
                change = (current['min'] - base['min']) / base['min'] * 100
                status = "✓" if change < 10 else "✗"
                print(f"{name}: {change:+.1f}% {status}")

# 使用
bench = PerformanceBenchmark('core_functions')
bench.add_test('sum_range', 'sum(range(1000))', number=10000)
bench.add_test('list_comp', '[i**2 for i in range(1000)]', number=1000)
bench.save_baseline()

CI集成基准测试

Python
# tests/test_benchmark.py

import pytest

@pytest.fixture
def benchmark_threshold():
    return {
        'sum_range': 0.03,  # 最大30ms
        'list_comp': 0.12,  # 最大120ms
    }

class TestPerformance:
    @pytest.mark.benchmark
    def test_sum_range(self, benchmark, benchmark_threshold):
        result = benchmark(sum, range(1000))
        assert benchmark.stats['mean'] < benchmark_threshold['sum_range']

    @pytest.mark.benchmark
    def test_list_comprehension(self, benchmark, benchmark_threshold):
        result = benchmark(lambda: [i**2 for i in range(1000)])
        assert benchmark.stats['mean'] < benchmark_threshold['list_comp']

性能测量精度对比

方法精度适用场景
time.time()毫秒级粗略测量
time.perf_counter()微秒级精确测量
timeit纳秒级代码片段
cProfile函数级整体分析
pytest-benchmark毫秒级自动化测试

注意:性能测试要多次运行取最优值,避免系统调度、GC等干扰因素。

要点总结

  • timeit测量代码片段,repeat多次运行取最优,autorange自动确定次数
  • pytest-benchmark集成测试框架,支持参数化、对比、保存基准
  • cProfile分析函数调用,pstats查看调用链和热点函数
  • 使用perf_counter高精度计时,禁用GC减少测量干扰
  • 建立基准体系:保存baseline、CI集成阈值检查、自动对比变化
  • 多参数范围测试,确保性能在各场景下稳定

存放路径articles/PYTHON/专家/性能优化/性能基准测试.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python字符串处理优化
下一篇 → Python数据结构性能优化
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库