【问题标题】:Caching compiled regex objects in Python?在 Python 中缓存已编译的正则表达式对象?
【发布时间】:2010-09-09 01:54:24
【问题描述】:

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

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

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

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

>>> 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

【问题讨论】:

  • 可悲的是,我的应用程序(900 个正则表达式和计数)也有这个问题。不幸的是,我在这个帖子中没有看到任何解决方案。

标签: python regex caching


【解决方案1】:

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

不容易。您必须编写一个自定义序列化程序,该序列化程序与 Python 正则表达式引擎的 C sre 实现挂钩。所需的时间和精力远远超过任何性能优势。

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

如果您的程序基本上只生成一次,编译一堆正则表达式,然后退出,您可以尝试重新设计它以在一次调用中执行多个测试。然后你可以像上面一样重复使用正则表达式。

最后,您可以将正则表达式编译成基于 C 的状态机,然后将它们与扩展模块链接。虽然这可能更难以维护,但它会完全从您的应用程序中消除正则表达式编译。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      首先,这是python re模块中的一个明显限制。它会限制正则表达式的合理程度和大小。长时间运行的进程限制更大,而命令行应用程序等短寿命进程的限制更小。

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

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

      【讨论】:

        【解决方案4】:

        shelve 模块似乎可以正常工作:

        
        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()
        
        

        然后您可以创建一个很好的包装类,它会自动为您处理缓存,使其对用户透明......留给读者的练习。

        【讨论】:

        • shelve 模块在内部使用pickle。这些模式仍然会在从架子上加载它们时重新编译。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          可以将每个正则表达式(或一组正则表达式)放入一个单独的文件中,然后使用 imp 模块动态导入您需要的文件。我怀疑它的扩展性很好,但它可能是你需要的。

          【讨论】:

          • 正则表达式仍需要显式或隐式编译,这需要时间。
          【解决方案7】:

          嗯,

          搁置不用泡菜吗?

          无论如何,我同意以前的回答者。由于一个模块只处理一次,我怀疑编译正则表达式将成为您的应用程序瓶颈。而且 Python re 模块速度很快,因为它是用 C 编码的 :-)

          但好消息是 Python 有一个不错的社区,所以我相信你可以找到目前正在破解你需要的东西的人。

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

          不知道它是否能做到,但如果没有,祝你研究顺利:-)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-01-13
            • 2011-08-31
            • 1970-01-01
            • 2013-01-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多