You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无侵入统计导入指定模块的所有脚本的执行时间

可行方案说明

完全可以在自研公共库层面实现全量逻辑,不需要修改任何一个现有业务脚本,核心是利用Python包导入初始化机制、栈帧检查、退出钩子三个特性实现,对业务代码零侵入。

具体实现逻辑

所有代码都写在自研公共库的__init__.py文件中——所有通过import *导入公共库的脚本,启动时都会自动执行该文件中的代码,不需要业务侧做任何改动。

  • 启动时间埋点:在__init__.py最顶部(所有其他业务逻辑导入之前)记录高精度启动时间,用time.perf_counter()保证耗时统计精度。
  • 调用方校验:通过Python标准库sys获取上层调用栈帧,也就是当前执行业务脚本的全局命名空间,做两个规则校验:
    • 检查指定的目标模块是否被导入到脚本全局空间
    • 检查全局空间中同名对象的来源是否为公共库内置模块,排除脚本内部自定义同名变量/模块的情况
  • 退出钩子注册:对校验通过的脚本,用标准库atexit注册退出回调函数,脚本正常执行结束、异常终止时都会自动触发回调,计算并打印总耗时,脚本路径可以直接从栈帧对象中获取,不需要额外传参。
可直接复用的代码示例

把下面的代码放到公共库__init__.py的最顶部,修改配置项后即可生效,后面接公共库原有的导入、导出逻辑即可:

import sys
import time
import atexit

# -------------------------- 配置项,按需修改 --------------------------
# 需要统计的公共库下的目标模块全路径
TARGET_MODULES = {
    "your_public_lib.utils",
    "your_public_lib.db_operator",
}
# 最小打印阈值,单位秒,低于该耗时的脚本不打印,填0则全量打印
MIN_COST_TO_PRINT = 0
# ---------------------------------------------------------------------

# 记录脚本启动时间,必须放在所有逻辑最前面
_script_start_ts = time.perf_counter()

# 获取业务脚本的栈帧、全局命名空间、脚本路径
_caller_frame = sys._getframe(1)
_caller_global_ns = _caller_frame.f_globals
_caller_script_path = _caller_frame.f_code.co_filename

# 校验是否符合统计规则
_need_stat = False
for _target_full_name in TARGET_MODULES:
    _target_short_name = _target_full_name.split(".")[-1]
    # 短名不存在于脚本全局空间,说明没导入该模块
    if _target_short_name not in _caller_global_ns:
        continue
    _exist_obj = _caller_global_ns[_target_short_name]
    # 校验对象来源,排除脚本自定义同名内容的情况
    if getattr(_exist_obj, "__name__", "") == _target_full_name:
        _need_stat = True
        break

# 符合规则才注册退出打印逻辑
if _need_stat:
    def _print_exec_cost():
        total_cost = time.perf_counter() - _script_start_ts
        if total_cost >= MIN_COST_TO_PRINT:
            print(f"\n[公共库耗时统计] 脚本路径: {_caller_script_path}")
            print(f"[公共库耗时统计] 总执行时长: {total_cost:.3f}s")
    atexit.register(_print_exec_cost)

# 后面继续写公共库原有的代码即可,比如原有模块导入、__all__定义等
注意事项
  • 所有统计逻辑用到的内部变量全部加下划线前缀,Python的import *默认不会导出下划线开头的名称,不会污染业务脚本的命名空间。
  • 整套逻辑只有栈帧检查、时间记录的微秒级开销,对业务脚本性能几乎无影响。
  • atexit注册的回调在脚本正常执行完成、抛出未捕获异常终止时都会触发,只有调用os._exit()强制杀进程的极端场景不会触发,常规业务场景完全覆盖。
  • 如果后续要新增统计的目标模块,只需要修改配置项里的TARGET_MODULES集合即可,不需要改动其他逻辑。

内容的提问来源于stack exchange,提问作者hanz hanzsolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:09:30