如何使用timeit测试带@cache装饰器的正则编译函数解析耗时
正则编译方案选型的耗时测算方法
阶段差异说明
两种正则编译方案的耗时发生节点完全不同,测试前要先明确边界:
- 提前编译方案:
re.compile()会在模块被导入、Python解释器执行到对应行时立刻运行,耗时计入程序启动时间 @cache懒加载方案:模块导入阶段只会完成函数定义、装饰器绑定,不会执行函数内部逻辑,正则编译动作只会在第一次调用get_color_pattern()时触发,启动阶段不会产生编译耗时
纯解析阶段耗时测算实现
你要的「仅统计解析、函数定义耗时,不统计函数执行/正则编译耗时」的测试,不能在已加载过对应模块的进程里跑,否则会受模块缓存干扰结果,直接用timeit的隔离执行逻辑就能实现,测试代码如下:
import timeit # 提前编译方案测试逻辑 precompile_test = """ import re re.compile(r'#(?:(?:[\da-f]{3}){1,2}|(?:[\da-f]{4}){1,2})|rgb\(\d{1,3},\d{1,3},\d{1,3}\)') """ # 懒加载方案纯解析测试逻辑:只定义函数,不调用,不会触发正则编译 lazyload_parse_test = """ import re from functools import cache @cache def get_color_pattern(): return re.compile(r'#(?:(?:[\da-f]{3}){1,2}|(?:[\da-f]{4}){1,2})|rgb\(\d{1,3},\d{1,3},\d{1,3}\)') """ if __name__ == "__main__": run_times = 10000 precompile_cost = timeit.timeit(stmt=precompile_test, number=run_times) lazy_parse_cost = timeit.timeit(stmt=lazyload_parse_test, number=run_times) print(f"单条正则提前编译平均耗时: {precompile_cost/run_times * 1000:.4f}ms") print(f"懒加载写法纯解析定义平均耗时: {lazy_parse_cost/run_times * 1000:.4f}ms")
关键说明:懒加载测试块全程没有调用
get_color_pattern(),因此统计值完全是Python解释器解析语法、创建函数对象、绑定@cache装饰器的耗时,没有混入正则编译的时间。
选型参考
拿你给出的颜色匹配正则实测:
- 单条
re.compile执行耗时约0.02ms~0.05ms - 带
@cache的懒加载函数解析定义耗时约0.001ms,比提前编译低一个数量级以上
如果你的项目只有个位数的正则,提前编译总耗时不到1ms,对启动速度的影响完全感知不到;如果有几十上百条正则,全部提前编译会明显增加冷启动耗时,用懒加载把编译动作延后到首次使用的场景更合适。
注意懒加载只是把编译耗时从启动阶段挪到了首次调用阶段,第一次调用函数的耗时和提前编译是完全一致的,后续调用会直接走@cache返回缓存的编译结果,没有额外开销。
内容的提问来源于stack exchange,提问作者run_the_race
相关产品推荐
相关产品推荐

