在Python中缓存已编译的regex对象?

时间:2020-03-05 18:54:09  来源:igfitidea点击:

每次导入包含大量静态正则表达式的python文件时,都会花费cpu周期将字符串编译到内存中的代表状态机中。

a = re.compile("a.*b")
b = re.compile("c.*d")
...

问题:是否可以通过预编译的方式将这些正则表达式存储在磁盘上的缓存中,从而避免在每次导入时都必须执行正则表达式编译?

腌制对象只是执行以下操作,无论如何都会导致编译:

>>> import pickle
>>> import re
>>> x = re.compile(".*")
>>> pickle.dumps(x)
"cre\n_compile\np0\n(S'.*'\np1\nI0\ntp2\nRp3\n."

re对象是不可编组的:

>>> import marshal
>>> import re
>>> x = re.compile(".*")
>>> marshal.dumps(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unmarshallable object

解决方案

回答

请注意,每个模块在应用程序的生命周期内仅初始化一次,无论我们导入了多少次。因此,如果我们在模块的全局范围内(即不在函数中)编译表达式,那应该没问题。

回答

Is it possible to store these regular expressions in a cache on disk in a pre-compiled manner to avoid having to execute the regex compilations on each import?

不容易。我们必须编写一个自定义的序列化程序,该序列化程序挂接到Python regex引擎的Csre实现中。所需的时间和精力将大大超过任何性能优势。

首先,我们是否实际配置过代码?我怀疑编译正则表达式是否是应用程序运行时的重要组成部分。请记住,它们仅在当前执行中第一次导入模块时进行编译-之后,模块及其属性将缓存在内存中。

如果程序基本上产生一次,编译一堆正则表达式,然后退出,则可以尝试对其进行重新设计以在一次调用中执行多个测试。然后,我们可以重新使用正则表达式,如上所述。

最后,我们可以将正则表达式编译为基于C的状态机,然后将其与扩展模块链接在一起。尽管这可能更难以维护,但是它将完全从应用程序中消除正则表达式编译。

回答

可以将每个正则表达式(或者正则表达式组)放入单独的文件中,然后使用imp模块动态导入所需的文件。我怀疑它的伸缩性是否很好,但这可能正是我们所需要的。

回答

搁置模块似乎可以正常工作:

import re
import shelve
a_pattern = "a.*b"
b_pattern = "c.*d"
a = re.compile(a_pattern)
b = re.compile(b_pattern)

x = shelve.open('re_cache')
x[a_pattern] = a
x[b_pattern] = b
x.close()

# ...
x = shelve.open('re_cache')
a = x[a_pattern]
b = x[b_pattern]
x.close()

然后,我们可以创建一个不错的包装器类,该类可以自动为我们处理缓存,从而使缓存对用户透明...这是读者的一项练习。

回答

哼,

不搁置泡菜吗?

无论如何,我同意以前的答案。由于模块仅处理一次,因此我怀疑编译正则表达式将成为我们应用程序的瓶颈。而且Python re模块使用C :-)进行编码,因此速度很快。

但是好消息是Python拥有一个不错的社区,所以我敢肯定,我们会发现目前有人在黑客我们需要的东西。

我用Google搜索了5秒,发现:http://home.gna.org/oomadness/en/cerealizer/index.html。

不知道它是否会做,但是如果做不到,那么请我们好运:-)

回答

打开/usr/lib/python2.5/re.py并查找" def _compile"。我们会发现re.py的内部缓存机制。

回答

首先,这是python re模块中的明显限制。它会限制合理的正则表达式数量和大小。长时间运行的进程的限制更大,而对于寿命短的进程(例如命令行应用程序),此限制则较小。

几年前,我确实看过它,可以挖掘出编译结果,对其进行腌制,然后对其进行剔除并重新使用。问题在于它需要使用sre.py内部结构,因此可能无法在不同的python版本中使用。

我想在我的工具箱中使用这种功能。我也想知道,是否可以使用任何单独的模块来代替。