Я пытаюсь выяснить нелогичную разницу в производительности между Python, Cython и чистым C с сопоставлением регулярных выражений.
Существует небольшая примерная программа, которая берет исходный текстовый файл (17 КБ), словарь из 2000 слов, создает регулярное выражение с этими словами (слово1|слово2|...) и находит все экземпляры указанного словаря в исходном файле. .
Во-первых, я сделал чистую реализацию Python, которая выглядит так:
def scanFile(filename, patterns):
pattern_regex = re.compile('|'.join(patterns))
pageContent = open(filename).read()
matchingPatterns = set()
for matchObj in pattern_regex.finditer(pageContent):
matchingPatterns.add(matchObj.group(0))
return matchingPatterns
Затем я попытался оптимизировать это, повторно реализовав то же самое с Cython, поверх модуля regex.h
, а не модуля re
Python.
cdef extern from "regex.h" nogil:
ctypedef struct regmatch_t:
int rm_so
int rm_eo
ctypedef struct regex_t:
pass
int REG_EXTENDED
int regcomp(regex_t* preg, const char* regex, int cflags)
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
void regfree(regex_t* preg)
def matchPatterns(bytes pageContent, bytes regex):
cdef set matchingPatterns = set()
cdef regex_t regex_obj
cdef regmatch_t regmatch_obj[1]
cdef int regex_res = 0
cdef int current_str_pos = 0
regcomp(®ex_obj, regex, REG_EXTENDED)
regex_res = regexec(®ex_obj, pageContent[current_str_pos:], 1, regmatch_obj, 0)
while regex_res == 0:
matchingPatterns.add(pageContent[current_str_pos + regmatch_obj[0].rm_so: current_str_pos + regmatch_obj[0].rm_eo])
current_str_pos += regmatch_obj[0].rm_eo
regex_res = regexec(®ex_obj, pageContent[current_str_pos:], 1, regmatch_obj, 0)
regfree(®ex_obj)
return matchingPatterns
Однако производительность оказалась как раз наоборот: Cython+regex.h занимает около 2,34 с, а Python — 0,92 с.
После небольшого профилирования и пользовательского закомментированного кода я подтвердил подозрение, что он равен regexec
, что занимает 10 миллисекунд при каждом вызове.
Просто чтобы убедиться, что виноват не Cython, подготовил автономный модульный тест C, который использует те же входные данные и regex.h, и он также показал худшие результаты, чем Python (около 1,60 с, т.е. на 60% медленнее, чем Python).
Итак, учитывая все это, я был бы признателен за любое понимание того, почему regexec
имеет такую низкую производительность.
Я использую это на Python 2.7.10, gcc 4.9.2, Cython 0.22 и платформе Cygwin/Windows. У меня было подобное несоответствие при запуске того же на Ubuntu.
set()
в Python, вы делали то же самое в C? - person cdarke   schedule 26.06.2015re
была намного хуже, чем boost::regex. Так как я хотел попробовать Cython (как опыт обучения, так и оптимизация), я выбрал regex.h, так как это чистый C. Я понимаю, что C++ можно включить в Cython и что boost::regex и regex.h не рождаются равными, но я надеялся получить одинаковые результаты в обоих случаях. Несоответствие вызвало вопрос. @cdarke - Действительно, вполне может быть, что с большим шаблоном OR Python справляется лучше. Однако из документации regex.h неясно, что он не хорошо справляется с этим. - person RomanK   schedule 26.06.2015boost::regex
даже быстрее). - person RomanK   schedule 26.06.2015