为什么在Python 3中未编译,重复使用的正则表达式如此之慢?

时间:2013-02-07 17:04:43

标签: python regex caching

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

但后来我想我会测试它,比较两种情况:

  1. 一个简单的正则表达式的单个汇编,然后是该编译的正则表达式的10个应用程序。
  2. 10个未编译正则表达式的应用程序(我预计性能稍差一些,因为正则表达式必须编译一次,然后缓存,然后在缓存中查找9次)。
  3. 然而,结果是惊人的(在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似乎没有暗示这一点。

1 个答案:

答案 0 :(得分:26)

代码更改。

在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 implementation of _compile()functools.lru_cache()

其他人注意到同样的减速,并在Python bugtracker中提交了issue 16389。我希望3.4再快一点; lru_cache实现得到改进,或re模块将再次移动到自定义缓存。

更新:使用revision 4b4dddd670d0,缓存更改已恢复为3.1中的简单版本。 Python版本3.2.4和3.3.1包含该版本。