Rom*_*anK 5 c python regex cython
我试图找出带有正则表达式匹配的Python,Cython和纯C之间的违反直觉的性能差异。
有一个小的示例程序,该程序使用源文本文件(17 KB),2000个单词的字典,并使用这些单词(word1 | word2 | ...)创建一个正则表达式,并在源文件中找到该词典的所有实例。 。
首先,我完成了一个纯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
Run Code Online (Sandbox Code Playgroud)
然后,我尝试通过使用Cython(regex.h而不是Python的re模块)重新实现相同的功能来优化此功能。
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
Run Code Online (Sandbox Code Playgroud)
然而,性能恰恰相反:Cython + regex.h大约需要2.34秒,而Python则需要0.92秒。
在运行了一些概要分析和自定义注释掉的代码后,我证实了怀疑,即regexec每次调用将花费10毫秒的时间。
为了确保不是Cython出了故障,准备了一个使用相同输入和regex.h的独立C单元测试,它还显示了比Python更差的结果(约1.60秒,即比Python慢60%)。
因此,对于所有这些原因,我将不胜感激,以感谢您对为何regexec如此差劲的表现表示感谢。
我在Python 2.7.10,gcc 4.9.2,Cython 0.22上运行,平台是Cygwin / Windows。在Ubuntu上运行时,我也有类似的差异。
根据问题中的内容,我可以假设几个问题: -您在 Windows 和 Cygwin 上使用 POSIX - 这是开销,Windows 不是 POSIX 系统。-pcre(让我假设 pcre2)和 regex.h 之间有比较 -独立编译的代码与导出的函数不同(编译器不能假设任何内容) -独立的 C 程序占用空间很大,告诉您正在重新编译模式或其他一些东西引擎盖。- 编译选项和潜在的别名总是很难比较。
除了独立程序的源代码之外,始终使用翻译器/转译器可能会产生滞后。如今,优化的任务是让编译器清楚地了解您正在做什么并让它工作。
对于这部分感到抱歉,与问题本身无关,但看起来您不需要 RE,而是需要基本的字符串匹配算法或一些简洁的结构(例如前缀树和简单循环)来完成您的任务。