使用 cProfile 和 line_profiler 进行性能分析
使用 cProfile 和逐行性能分析找出 CPU 性能热点。
使用 cProfile 和 line_profiler 进行性能分析 是 CoddyKit 上的免费 Python Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。
为什么要进行性能分析
性能分析可以找出最耗时的函数,从而指导优化工作。请始终在优化之前进行性能分析,不要凭猜测行事。
import cProfile
def slow():
total = 0
for i in range(1_000_000):
total += i
return total
cProfile.run("slow()")从命令行运行 cProfile
无需修改脚本即可分析整个脚本:python -m cProfile -s cumtime script.py。您可以按 cumtime、tottime 或 calls 排序。
# python -m cProfile -s cumtime my_script.py
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1000 0.500 0.001 2.100 0.002 utils.py:10(process)代码中的 cProfile
创建一个 cProfile.Profile,启用或禁用它,然后使用 pstats 输出统计信息。
import cProfile, pstats, io
pr = cProfile.Profile()
pr.enable()
# ... code to profile ...
pr.disable()
stream = io.StringIO()
ps = pstats.Stats(pr, stream=stream).sort_stats("cumulative")
ps.print_stats(10) # top 10
print(stream.getvalue())pstats 筛选
使用 print_stats(pattern),根据特定模块或函数名称模式筛选分析器输出。
import cProfile, pstats
cProfile.run("my_function()", "profile.out")
stats = pstats.Stats("profile.out")
stats.sort_stats("tottime")
stats.print_stats("mymodule") # only mymodule functionsline_profiler
line_profiler 会显示每一行的执行时间,而不仅仅是每个函数的执行时间,这对于找出函数内部最耗时的代码行至关重要。
# pip install line_profiler
# Decorate target function:
from line_profiler import profile
@profile
def process(data):
result = []
for item in data: # <- which line is slow?
result.append(item*2)
return result
# Run: kernprof -l -v script.pykernprof CLI
kernprof -l script.py 会在启用逐行分析的情况下运行脚本;-v 会立即显示报告。
# kernprof -l -v script.py
#
# Line # Hits Time Per Hit % Time Line Contents
# ======================================================
# 4 1 2.0 2.0 1.0 result = []
# 5 1000 120.0 0.1 60.0 for item in data:
# 6 1000 80.0 0.1 39.0 result.append(item*2)Jupyter 中的分析
Jupyter 提供 %prun(cProfile)和 %lprun(line_profiler)魔术命令。
# In a Jupyter cell:
# %prun -s cumulative my_function(data)
# %load_ext line_profiler
# %lprun -f my_function my_function(data)识别热点
请重点关注具有最高累计时间的函数(整个调用链),以及具有最高总时间的函数(不包括被调用函数,仅计算函数自身)。
# cumtime = total time including callees (find root cause)
# tottime = time in function itself (find where work happens)
#
# Optimise the function with highest tottime first避免过早优化
先进行分析,再优化测量得到的瓶颈。常见的 Python 加速方法包括:使用内置功能,将循环移到 NumPy 中,缓存重复查找的结果,或通过 ctypes/cffi 调用 C。
# Before optimising:
# profile shows: process_row() 95% of time
# Speedup: vectorise with NumPy
import numpy as np
arr = np.array(data)
result = arr * 2 # 100x faster than Python looppy-spy:采样分析器
py-spy 无需修改代码即可分析正在运行的进程,您可以附加到正在运行的 PID。
# pip install py-spy
# Profile for 30 s and show flamegraph:
# py-spy top --pid 12345
# py-spy record -o profile.svg --pid 12345 --duration 30使用 timeit 进行基准测试
使用 timeit 对特定表达式进行微基准测试。
import timeit
result = timeit.timeit(
"[x*2 for x in range(1000)]",
number=10_000
)
print(f"{result:.3f} s for 10k runs")快速检查
在 cProfile 报告中,tottime 显示什么?
回顾
使用 cProfile 找出运行缓慢的函数,使用 line_profiler 找出运行缓慢的代码行。使用 -s cumtime 进行分析,以找出根本原因。只优化已确认的热点,并使用 NumPy 向量化、缓存或 C 扩展来获得最大的性能提升。
常见问题解答
「使用 cProfile 和 line_profiler 进行性能分析」课时是免费的吗?
是的 — 「使用 cProfile 和 line_profiler 进行性能分析」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。
「使用 cProfile 和 line_profiler 进行性能分析」这节课中我会学到什么?
使用 cProfile 和逐行性能分析找出 CPU 性能热点。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Python Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「使用 cProfile 和 line_profiler 进行性能分析」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Python Academy 课中编写并运行代码吗?
能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- CPython 引用计数
- 垃圾回收器与循环引用
- 使用 cProfile 和 line_profiler 进行性能分析
- 使用 tracemalloc 进行内存分析