Кеширование скомпилированных объектов регулярных выражений в Python? - PullRequest
18 голосов
/ 15 сентября 2008

Каждый раз, когда импортируется файл python, содержащий большое количество статических регулярных выражений, циклы ЦП тратятся на компиляцию строк в их представительные автоматы в памяти.

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

Ответы [ 7 ]

13 голосов
/ 15 сентября 2008

Можно ли хранить эти регулярные выражения в кэше на диске предварительно скомпилированным образом, чтобы избежать необходимости выполнять регулярные выражения при каждом импорте?

Не легко. Вам нужно написать собственный сериализатор, который подключается к реализации C sre движка регулярных выражений Python. Любые преимущества в производительности будут значительно перевешены затратами времени и усилий.

Во-первых, вы действительно профилировали код? Я сомневаюсь, что компиляция регулярных выражений является важной частью времени выполнения приложения. Помните, что они компилируются только при первом импорте модуля в текущем исполнении - после этого модуль и его атрибуты кэшируются в памяти.

Если у вас есть программа, которая в основном порождается один раз, компилирует кучу регулярных выражений, а затем завершает работу, вы можете попробовать перепроектировать ее для выполнения нескольких тестов за один вызов. Затем вы можете повторно использовать регулярные выражения, как указано выше.

Наконец, вы можете скомпилировать регулярные выражения в конечные автоматы на основе Си, а затем связать их с модулем расширения. Хотя это, вероятно, будет сложнее поддерживать, это полностью исключит компиляцию регулярных выражений из вашего приложения.

2 голосов
/ 15 сентября 2008

Обратите внимание, что каждый модуль инициализирует себя только один раз в течение жизни приложения, независимо от того, сколько раз вы его импортировали. Так что, если вы скомпилируете свои выражения в глобальной области видимости модуля (т.е. не в функции), все будет в порядке.

1 голос
/ 28 декабря 2008

Прежде всего, это явное ограничение в модуле python re. Это приводит к ограничению, насколько разумными являются большие регулярные выражения. Ограничение больше для долго выполняющихся процессов и меньше для краткосрочных процессов, таких как приложения командной строки.

Несколько лет назад я посмотрел на него, и можно выкопать результат компиляции, засолить его, а затем открепить и использовать повторно. Проблема в том, что он требует использования внутренних компонентов sre.py и поэтому не будет работать в разных версиях Python.

Я хотел бы иметь такую ​​функцию в своем наборе инструментов. Я также хотел бы знать, есть ли какие-то отдельные модули, которые могли бы использоваться вместо этого.

0 голосов
/ 16 сентября 2008

Откройте /usr/lib/python2.5/re.py и найдите «def _compile». Вы найдете механизм внутреннего кэша re.py.

0 голосов
/ 16 сентября 2008

Hum

Разве на полке не используется рассол?

В любом случае, я согласен с предыдущими ответами. Поскольку модуль обрабатывается только один раз, я сомневаюсь, что компиляция регулярных выражений станет для вас узким местом. И модуль Python re работает быстро, так как он написан на C: -)

Но хорошая новость в том, что у Python хорошее сообщество, поэтому я уверен, что вы можете найти кого-то, кто сейчас взламывает именно то, что вам нужно.

Я погуглил 5 секунд и нашел: http://home.gna.org/oomadness/en/cerealizer/index.html.

Не знаю, удастся ли это, но если нет, то удачи в ваших исследованиях: -)

0 голосов
/ 15 сентября 2008

Модуль полка работает нормально:


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

Затем вы можете создать хороший класс-обертку, который автоматически обрабатывает кэширование для вас, чтобы он стал прозрачным для пользователя ... упражнение, оставленное для читателя.

0 голосов
/ 15 сентября 2008

Можно поместить каждое регулярное выражение (или группу регулярных выражений) в отдельный файл, а затем динамически импортировать нужный файл с помощью модуля imp. Я сомневаюсь, что это очень хорошо масштабируется, но это может быть то, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...