为什么c ++ 11 regex(libc ++实现)如此之慢?
我与Linux C正则表达式库比较,
#include #include #include int main() { const int count = 100000; regex_t exp; int rv = regcomp(&exp, R"_(([a-zA-Z][a-zA-Z0-9]*)://([^ /]+)(/[^ ]*)?)_", REG_EXTENDED); if (rv != 0) { std::cout << "regcomp failed with " << rv << std::endl; } auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < count; i++) { regmatch_t match; const char *sz = "http://www.abc.com"; if (regexec(&exp, sz, 1, &match, 0) == 0) { // std::cout << sz << " matches characters " << match.rm_so << " - " << match.rm_eo << std::endl; } else { // std::cout << sz << " does not match" << std::endl; } } auto end = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast(end - start); std::cout << elapsed.count() << std::endl; return 0; }
结果在我的测试机器上大约是60-70毫秒。
然后我使用了libc ++的库,
#include #include #include int main() { const int count = 100000; std::regex rgx(R"_(([a-zA-Z][a-zA-Z0-9]*)://([^ /]+)(/[^ ]*)?)_", std::regex_constants::extended); auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < count; i++) { std::cmatch match; const char sz[] = "http://www.abc.com"; if (regex_search(sz, match, rgx)) { } else { } } auto end = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast(end - start); std::cout << "regex_search: " << elapsed.count() << std::endl; start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < count; i++) { const char sz[] = "http://www.abc.com"; if (regex_match(sz, rgx)) { } else { } } end = std::chrono::high_resolution_clock::now(); elapsed = std::chrono::duration_cast(end - start); std::cout << "regex_match: " << elapsed.count() << std::endl; return 0; }
regex_search和regex_match的结果大约是2秒。 这比C的regex.h库慢大约30倍。
我的比较有什么不对吗? C ++的正则表达式库不适用于高性能案例吗?
我可以理解它很慢,因为c ++的正则表达式库还没有优化,但速度慢了30倍。
谢谢。
大家好,
谢谢回答。
抱歉我的错误我也使用了[] C,但后来我改变了,忘了改变C ++代码。
我做了两个改变,
- 我将const char sz []移出了C&C ++的循环。
- 我用-O2编译它(之前我没有使用任何优化),C库的实现仍然是大约60毫秒,但是libc ++的正则表达式现在给出了一个数字,regex_search为1秒,regex_match为150毫秒。
这仍然有点慢,但没有原始比较那么多。
如果你看一下http://llvm.org/svn/llvm-project/libcxx/trunk/include/regex,你会看到regex_match
这个实现是在regex_search
上面的分层,并且所有重载都提取子表达式匹配位置甚至如果只是被扔掉的当地临时演员。 regex_search
使用__state
对象的vector
, __state
对象在它们上面调用了.resize()
,因此可能也是向量 – 当子表达式匹配时不需要所有堆分配和不必要,但是需要跟踪perl-中的\1
等正则表达式的样式扩展:旧的regcomp
/ regexec
C函数没有提供那些扩展function,从来不需要做额外的工作。 当然,如果clang实现检查了正则表达式在编译期间跟踪匹配的需要并调用更精简,更快的函数以便在可能的情况下进行匹配,那将是很好的,但我猜他们只是从支持一般情况开始。
以下两行不做同样的事情!
const char sz1[] = "http://www.abc.com"; const char* sz2 = "http://www.abc.com";
这已经足以使它成为一个不公平的考验。
sz
和match
是循环不变的,你应该将它们移到之前(在两种情况下都是sz
)。
在第二种情况下, sz
是初始化数组而不是指向常量字面的指针 – 这是一种不公平且不必要的差异。 也就是说,如果你按照建议将声明移到循环之前,那应该没什么区别。
尽管regex_search()
为const const char*
重载,可能在内部导致构造std::string
,但为了避免这种可能性,你应该用以下方法测试它:
const std::string sz( "http://www.abc.com" ) ;
(再次在循环之前 )。
所以测试:
std::cmatch match; const char* = "http://www.abc.com"; for (int i = 0; i < count; i++) { if (regex_search(sz, match, rgx)) { } else { } }
和
std::cmatch match; const std::string sz( "http://www.abc.com" ) for (int i = 0; i < count; i++) { if (regex_search(sz, match, rgx)) { } else { } }