在回答 this question 时(并且已经阅读了 this answer 到一个类似的问题),我认为我知道 Python 如何缓存正则表达式。
但后来我想我会测试一下,比较两个场景:
- 一个简单的正则表达式的单一编译,然后是该已编译正则表达式的 10 个应用程序。
- 未编译的正则表达式的 10 个应用程序(我预计性能会稍差,因为正则表达式必须编译一次,然后缓存,然后在缓存中查找 9 次)。
然而,结果却是惊人的(在 Python 3.3 中):
>>> import timeit
>>> timeit.timeit(setup="import re",
... stmt='r=re.compile(r"\w+")\nfor i in range(10):\n r.search(" jkdhf ")')
18.547793477671938
>>> timeit.timeit(setup="import re",
... stmt='for i in range(10):\n re.search(r"\w+"," jkdhf ")')
106.47892003890324
慢了 5.7 倍以上!在 Python 2.7 中,仍然增加了 2.5 倍,这也超出了我的预期。
在 Python 2 和 3 之间,正则表达式的缓存是否发生了变化? The docs似乎不建议这样做。
最佳答案
代码已经改变了。
在 Python 2.7 中,缓存是一个简单的字典;如果其中存储了超过 _MAXCACHE
个项目,则在存储新项目之前清除整个缓存。缓存查找只需要构建一个简单的键并测试字典,参见 2.7 implementation of _compile()
在 Python 3.x 中,缓存已替换为 @functools.lru_cache(maxsize=500, typed=True)
decorator .这个装饰器做了更多更多的工作,包括一个线程锁、调整缓存 LRU 队列和维护缓存统计信息(可通过 re._compile.cache_info()
访问)。见 3.3.0 implementation of _compile()
和 functools.lru_cache()
.
其他人也注意到了同样的放缓,并提交了 issue 16389在 Python 错误跟踪器中。我希望 3.4 会再次快很多。 lru_cache
实现得到改进,或者 re
模块将再次移动到自定义缓存。
更新:使用 revision 4b4dddd670d0 (hg) / 0f606a6 (git)缓存更改已恢复为 3.1 中的简单版本。 Python 版本 3.2.4 和 3.3.1 包含该修订版。
从那时起,在 Python 3.7 中,模式缓存更新为 custom FIFO cache implementation基于常规 dict
(依赖于插入顺序,并且与 LRU 不同,在驱逐时不考虑已在缓存中的项目最近使用的时间)。
关于python - 为什么在 Python 3 中未编译的、重复使用的正则表达式要慢得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14756790/