python - 为什么在 Python 3 中未编译的、重复使用的正则表达式要慢得多?

标签 python regex caching

在回答 this question 时(并且已经阅读了 this answer 到一个类似的问题),我认为我知道 Python 如何缓存正则表达式。

但后来我想我会测试一下,比较两个场景:

  1. 一个简单的正则表达式的单一编译,然后是该已编译正则表达式的 10 个应用程序。
  2. 未编译的正则表达式的 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/

相关文章:

python - 运行 IPyhon.widgets 时没有名为 'ipywidgets' 的模块错误

python - 将每个 var 输入写入文本文件中的新行

c# - EAN128 或 GS​​1-128 解码 c#

java - Apache Ignite 具有对象类型的索引字段

python - 使用 Flask 的 "after_request"处理程序获取错误回溯

python - 字符串的正则表达式

.net - 全局正则表达式匹配超时适用于控制台应用程序,但不适用于 ASP.NET MVC 应用程序

qt - QPainter 缓存可能吗?

caching - 在 ASP.NET 5 中缓存模式是否有任何指导

python - json.decoder.JSONDecodeError : Expecting value: line 1 column 1 (char 0) python