如何用cProfile等内置模块实时追踪Python插件函数执行?
使用cProfile及内置模块实现Python插件的实时模块性能分析
不需要手动给每个函数加装饰器,以下几种方案可以快速实现指定模块的函数执行情况监控,实时输出到控制台:
方案1:用cProfile定向分析指定模块
通过cProfile生成完整性能数据后,过滤只显示目标模块的结果,无需修改插件代码:
import cProfile import pstats from my_blender_plugin import run_plugin # 替换为你的插件模块和入口函数 # 启动性能分析 pr = cProfile.Profile() pr.enable() run_plugin() # 执行插件的核心逻辑 pr.disable() # 过滤并打印目标模块的统计数据 stats = pstats.Stats(pr) stats.strip_dirs() # 简化函数路径显示 stats.sort_stats('cumulative') # 按累计耗时排序,可选'time'按单次耗时排序 stats.print_stats('my_blender_plugin') # 替换为你的目标模块名,只显示该模块的函数
方案2:用sys.setprofile实现实时函数调用追踪
如果需要实时输出每个函数的调用/返回及耗时,可以用Python内置的sys.setprofile钩子,自动追踪指定模块的函数:
import sys import time from my_blender_plugin import run_plugin # 替换为你的插件模块和入口函数 TARGET_MODULE = 'my_blender_plugin' # 替换为你的目标模块名 func_start_times = {} def profile_hook(frame, event, arg): # 只处理目标模块的函数调用和返回事件 module_name = frame.f_globals.get('__name__') if module_name != TARGET_MODULE: return profile_hook if event == 'call': func_name = frame.f_code.co_name func_start_times[frame] = time.perf_counter() print(f"[调用] {module_name}.{func_name}") elif event == 'return' and frame in func_start_times: elapsed = time.perf_counter() - func_start_times.pop(frame) func_name = frame.f_code.co_name print(f"[返回] {module_name}.{func_name} - 耗时: {elapsed:.6f}秒") return profile_hook # 启动追踪并执行插件 sys.setprofile(profile_hook) try: run_plugin() finally: sys.setprofile(None) # 必须关闭追踪,避免影响后续代码
方案3:结合cProfile实现带统计的实时输出
如果需要更精准的性能指标(调用次数、累计耗时等)同时实时输出,可以在插件逻辑执行完成后立即打印统计结果:
import cProfile import pstats from my_blender_plugin import run_plugin # 替换为你的插件模块和入口函数 TARGET_MODULE = 'my_blender_plugin' def real_time_stat_profile(): pr = cProfile.Profile() pr.enable() # 执行插件逻辑(如果是按钮触发,可将此部分绑定到按钮点击事件) run_plugin() pr.disable() # 实时打印目标模块的性能统计 stats = pstats.Stats(pr) stats.strip_dirs() stats.sort_stats('time') print(f"\n=== {TARGET_MODULE} 性能统计结果 ===") stats.print_stats(TARGET_MODULE) real_time_stat_profile()
注意事项
- 针对Blender插件:Blender的Python环境兼容cProfile和sys.setprofile,直接使用即可;若为UI触发逻辑,只需将分析代码绑定到按钮的点击回调中。
- 性能开销:
sys.setprofile会带来一定性能损耗,若插件对性能敏感,优先选择方案1或方案3。 - 自定义过滤:可扩展
profile_hook逻辑,比如只追踪类的成员函数(通过检查frame.f_locals.get('self')是否存在)。
内容的提问来源于stack exchange,提问作者DB3D
相关产品推荐
相关产品推荐

