regex.h性能

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(&regex_obj, regex, REG_EXTENDED)
   regex_res = regexec(&regex_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(&regex_obj, pageContent[current_str_pos:], 1, regmatch_obj, 0)

   regfree(&regex_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上运行时,我也有类似的差异。

Evi*_*vil 1

根据问题中的内容,我可以假设几个问题: -您在 Windows 和 Cygwin 上使用 POSIX - 这是开销,Windows 不是 POSIX 系统。-pcre(让我假设 pcre2)和 regex.h 之间有比较 -独立编译的代码与导出的函数不同(编译器不能假设任何内容) -独立的 C 程序占用空间很大,告诉您正在重新编译模式或其他一些东西引擎盖。- 编译选项和潜在的别名总是很难比较。

除了独立程序的源代码之外,始终使用翻译器/转译器可能会产生滞后。如今,优化的任务是让编译器清楚地了解您正在做什么并让它工作。

对于这部分感到抱歉,与问题本身无关,但看起来您不需要 RE,而是需要基本的字符串匹配算法或一些简洁的结构(例如前缀树和简单循环)来完成您的任务。