当前位置:首页 > 文章列表 > 文章 > python教程 > Python profile 和 cProfile 的计时开销有什么区别

Python profile 和 cProfile 的计时开销有什么区别

来源:17golang原创 2026-10-29 18:29:45 0浏览 收藏

profile 的纯 Python 实现会给被测程序带来较明显的事件处理开销;cProfile 使用 C 扩展,通常更适合日常定位热点。但“开销较低”不等于零开销,也不能给出对所有程序通用的减速倍数。两者报表用于找时间花在哪里,比较代码方案快慢应另做无剖析计时。

Python 剖析工具官方文档:https://docs.python.org/3.14/library/profile.html

本文示例明确采用 CPython 3.14 的接口。较新的 Python 文档对工具组织和弃用状态已有调整:当前 profile 文档 标注其自 3.15 弃用、计划在 3.17 移除,并说明 cProfile 作为兼容别名保留。运行环境不同,应先看对应版本文档,不把本例当作所有版本的长期部署方案。

先把小项目的观察目标说清楚

一个文本汇总脚本可能没有复杂算法,却反复调用小函数。给它加上剖析器后,总耗时可能发生明显变化。如果据此认定业务函数突然变慢,就混入了观察工具自身的成本。

我会把这类判断拆为两项:先用 cProfile 看调用结构和高累计耗时函数,再脱离剖析器测原任务。这里表达的是工具选择方法,并非声称做过本文这组实测。小项目只输出输入一致的校验值、外部经过时间和函数报表,不预填任何性能数字。

同一业务任务与两种剖析器及外部计时边界
结构说明图:profile 与 cProfile 是替代的观察方式,外部计时覆盖任务和剖析开销;连线不表示执行先后。

用同一个任务接入两种剖析器

保存为 profiler_probe.py。代码为本文原创,未在制作过程中执行;读者运行时得到的数据才是对应环境的观察值。

import argparse
import cProfile
import platform
import profile
import pstats
import time

def token_score(text):
    # 刻意保留小函数调用,以便观察调用密集型任务。
    return len(text.strip().casefold())

def summarize(lines):
    total = 0
    for text in lines:
        total += token_score(text)
    return total

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("mode", choices=("baseline", "profile", "cprofile"))
    args = parser.parse_args()
    # 所有模式共用相同输入;数据准备与导入不在观察区间内。
    lines = (" Alpha ", "Beta", " GAMMA ") * 20000
    profiler = None
    if args.mode == "profile":
        profiler = profile.Profile()
    elif args.mode == "cprofile":
        profiler = cProfile.Profile()

    start = time.perf_counter()
    if profiler is None:
        result = summarize(lines)
    else:
        # 两个类都支持 runcall,避免误用 profile 不支持的 enable。
        result = profiler.runcall(summarize, lines)
    elapsed = time.perf_counter() - start
    print(platform.python_implementation(), platform.python_version())
    print("mode=", args.mode, "checksum=", result, "elapsed_s=", elapsed)
    if profiler is not None:
        # 报表格式化放到外部计时结束后,单独观察函数累计时间。
        pstats.Stats(profiler).strip_dirs().sort_stats(
            pstats.SortKey.CUMULATIVE
        ).print_stats(8)

if __name__ == "__main__":
    main()
# 在同一 CPython 3.14 环境分别运行;每条命令建立独立进程。
python profiler_probe.py baseline
python profiler_probe.py profile
python profiler_probe.py cprofile

输入构造、模块导入与报表打印都放在外部计时区间之外,便于围绕一次 summarize 调用讨论。剖析器对象也提前创建;因此这不是整进程启动时间比较。runcall 的包装开销仍计入带剖析器的外部耗时,正是此处希望观察的部分。

checksum 用来提示读者三个模式是否仍处理同一个任务,不是性能数据。某次结果不同,应先解释输入或逻辑差异,再谈耗时。单轮很短时不要把小数位差异直接解释为真实改进,也不要把一条结果当作工具固定开销。

解释开销为什么不只是一次读时钟

剖析器需要响应函数调用、返回等事件并维护统计。profile 在 Python 层处理这些工作,cProfile 的核心由 C 实现,成本不同。任务的函数调用密度也会影响观察扰动;大量短函数与少量长调用不能简单套同一个比例。这与 3.14 官方介绍 对两种实现的定位一致。

外部耗时与剖析报表内部统计的含义关系
结构说明图:外部经过时间与函数内部、累计时间的口径不同;图中没有实测数值或性能排名。
观察项用途不应作出的推论
外部 elapsed_s观察该调用区间的整体经过时间等同于某一行报表的时间
ncalls观察调用数量调用最多就是最值得优化
tottime关注函数自身耗时包含其全部子调用成本
cumtime关注函数连同子调用的累计耗时各行相加等于总耗时

报表中上层与下层的累计时间会覆盖同一段调用,所以不能把 cumtime 列逐行累加为总量。本文没有给两个剖析器强行配置相同自定义时钟;外部统一使用 perf_counter,只保证外部观察区间的时钟口径一致,不能由此声称内部记账误差也完全相同。

把速度判断放回无剖析测量

如果目标是判断修改后的 summarize 是否更快,就把被测代码放在不启用任何剖析器的环境中。下面单独保存为 timing_probe.py,与前一个文件放在一起:

import timeit
from profiler_probe import summarize

# 使用同一份输入,脱离剖析器再观察任务耗时;不自动证明优化有效。
lines = (" Alpha ", "Beta", " GAMMA ") * 20000
samples = timeit.repeat(lambda: summarize(lines), number=10, repeat=5)
print("每轮十次调用的秒数:", samples)

根据 timeit 官方说明,repeat 返回多次计时结果,number 是每轮执行次数。此处每项是十次调用的总秒数,不是单次耗时;若展示单次值,应除以十并标明单位。timeit 默认暂时关闭垃圾回收,若任务依赖回收成本,应明确采用相应设置,而不是把结果直接等同于实际服务延迟。

至少随结果保留解释器版本、平台、输入规模和测量范围。同一机器交替观察不同模式与候选方案,可减少固定顺序带来的误判;仍需留意系统负载和预热。本文脚本只帮助读者形成可比较的记录,没有自动计算“profile 比 cProfile 慢几倍”的结论。

常见问题

profile 的校准能消除运行变慢吗?

校准用于补偿统计中的部分事件开销,不会让已发生的处理时间消失。它也不是可跨机器、跨计时器直接复用的万能常数。不需要研究或扩展纯 Python 剖析实现时,通常没有必要为日常热点定位选它。

cProfile 能直接证明 Python 写法不如 C 函数快吗?

不能直接根据带剖析器的结果做这种基准判断。两种实现被观测时的扰动可能不同,应把结论限制在热点线索,再用脱离剖析器、输入一致的测量回答速度问题。

示例可以放进生产请求里长期运行吗?

这份小项目用于开发环境理解开销和口径。它打印报表,也没有服务隔离、请求采样或并发治理设计,不能直接当作生产监控方案。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python pstats 怎样同时限制性能报告的排序和显示条目Python pstats 怎样同时限制性能报告的排序和显示条目
上一篇
Python pstats 怎样同时限制性能报告的排序和显示条目
Python aifc 被移除后怎样选择 AIFF 音频处理路径
下一篇
Python aifc 被移除后怎样选择 AIFF 音频处理路径
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    777次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    773次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    858次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    824次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    652次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码