5.8 KiB
5.8 KiB
TimeCost 性能计时工具技术文档
概述
TimeCost 是一个基于上下文管理器(Context Manager)的轻量级 Python 性能分析工具,用于记录代码块的执行时间。它通过装饰器模式和全局字典 timerecord 累积多个调用的时间开销,便于后续统计与分析。
该模块适用于开发调试、性能优化等场景,支持按名称分类记录耗时,并提供清除和展示功能。
注意:此模块依赖于标准库
time和datetime,并使用了自定义的单例装饰器SingletonDecorator(当前未使用,但已导入)。
模块依赖
import time
import datetime
from .Singleton import SingletonDecorator
time: 用于获取高精度时间戳。datetime: 当前未实际使用,可考虑移除以减少冗余。SingletonDecorator: 导入但未在类中应用,可能为预留扩展功能。
全局变量
timerecord = {}
- 类型:字典(
dict) - 键(key):字符串,表示计时任务的名称。
- 值(value):浮点数列表,存储每次该任务的执行耗时(单位:秒)。
示例:
{
"database_query": [0.12, 0.15, 0.11],
"file_load": [0.45, 0.38]
}
核心类:TimeCost
类定义
class TimeCost:
def __init__(self, name):
self.name = name
- 作用:初始化一个以
name命名的计时器。 - 参数:
name(str): 计时任务的标识名称,用于区分不同的代码段。
上下文管理器方法
__enter__
def __enter__(self):
self.begin_time = time.time()
- 在进入
with语句块时自动调用。 - 记录当前时间作为起始时间戳(
begin_time),单位为秒(float)。
__exit__
def __exit__(self, *args):
self.end_time = time.time()
d = timerecord.get(self.name, [])
d.append(self.end_time - self.begin_time)
timerecord[self.name] = d
- 在退出
with语句块时自动调用。 - 计算耗时(
end_time - begin_time),并将结果追加到对应名称的计时列表中。 - 若该名称首次出现,则创建新列表。
方法说明
clear(self)
def clear(self):
timerecord = {}
⚠️ 注意:此方法存在严重缺陷
- 此处的
timerecord = {}仅在局部作用域内重新绑定变量,不会修改外部全局字典。 - 实际上 无任何效果。
✅ 建议修复方案:
def clear(self):
timerecord.clear() # 清空全局字典内容
@classmethod clear_all(cls)
@classmethod
def clear_all(cls):
timerecord = {}
⚠️ 同样存在问题:局部赋值无法影响全局
timerecord
✅ 正确实现应为:
@classmethod
def clear_all(cls):
timerecord.clear()
或:
@classmethod
def clear_all(cls):
global timerecord
timerecord = {}
@classmethod clear(cls, name)
@classmethod
def clear(cls, name):
timerecord[name] = []
- 清除指定名称的所有历史耗时记录。
- 如果
name不存在,会自动创建一个空列表。 - ✅ 此方法是线程不安全的,但在单线程环境下可用。
@classmethod show(cls)
@classmethod
def show(cls):
def getTimeCost(name):
x = timerecord.get(name, [])
if len(x) == 0:
return 0, 0, 0
return len(x), sum(x), sum(x)/len(x)
print('TimeCost ....')
for name in timerecord.keys():
print(name, *getTimeCost(name))
- 打印所有已记录任务的统计信息。
- 输出格式:
<name> <调用次数> <总耗时> <平均耗时> - 示例输出:
TimeCost .... database_query 3 0.38 0.127 file_load 2 0.83 0.415
子函数 getTimeCost(name)
- 返回三元组:
(调用次数, 总耗时, 平均耗时) - 若无记录,则返回
(0, 0, 0)
使用示例
基本用法
from your_module import TimeCost
# 测量某段代码的执行时间
with TimeCost("test_function"):
time.sleep(1)
with TimeCost("test_function"):
time.sleep(0.5)
# 显示统计结果
TimeCost.show()
输出示例:
TimeCost ....
test_function 2 1.5 0.75
清除记录
# 清除特定任务记录
TimeCost.clear("test_function")
# 或清除全部(需修复后才有效)
TimeCost.clear_all()
已知问题与改进建议
| 问题 | 描述 | 建议 |
|---|---|---|
clear() 方法无效 |
局部变量赋值无法修改全局状态 | 改用 timerecord.clear() 或 global 关键字 |
clear_all() 方法无效 |
同上 | 同上 |
datetime 未使用 |
冗余导入 | 可移除 |
| 非线程安全 | 多线程下可能产生竞争条件 | 如需并发支持,应加锁机制 |
| 缺少持久化/导出功能 | 仅支持打印 | 可增加 .to_dict() 或 .export_json() 方法 |
安全性与注意事项
- 该类不是线程安全的。多线程环境中使用可能导致数据错乱。
- 所有计时数据保存在内存中,程序重启后丢失。
- 名称冲突会导致数据合并,请确保不同逻辑使用唯一
name。
总结
TimeCost 提供了一种简洁优雅的方式对代码块进行性能采样,适合快速定位性能瓶颈。尽管目前存在一些作用域相关的 bug,但结构清晰、易于理解和扩展。
经适当修复后,可作为项目中的轻量级性能监控组件。
📌 推荐修复后的完整类片段(关键部分):
@classmethod
def clear_all(cls):
timerecord.clear() # 或使用 global timerecord; timerecord = {}
def clear(self):
timerecord.clear()
@classmethod
def clear(cls, name):
timerecord[name] = []