为什么 C++11 正则表达式(libc ++ 实现)如此缓慢?

why c++11 regex (libc++ implementation) is so slow?

本文关键字:缓慢 实现 C++11 正则表达式 libc 为什么      更新时间:2023-10-16

I 与 Linux C 正则表达式库相比,

#include <iostream>
#include <chrono>
#include <regex.h>
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<std::chrono::microseconds>(end - start);
std::cout << elapsed.count() << std::endl;
return 0;
}

在我的测试机器上,结果大约是 60-70 毫秒。

然后我使用了libc++的库,

#include <iostream>
#include <chrono>
#include <regex>

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<std::chrono::microseconds>(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<std::chrono::microseconds>(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++代码。

我做了两个更改,

  1. 我将 const char sz[] 移出了 C 和 C++ 的循环。
  2. 我用 -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,这些对象.resize()调用它们,所以大概也是向量 - 当不需要子表达式匹配时,所有堆分配和不必要的,但需要跟踪以支持正则表达式的perl样式扩展中的1等:旧的regcomp/regexecC函数没有提供那些扩展功能,永远不必做这些额外的工作。 当然,如果 clang 实现在编译期间检查正则表达式对跟踪匹配的需求并在可能的情况下调用更精简、更快的函数进行匹配,那就太好了,但我想他们只是从支持一般情况开始。

以下两行做同样的事情!

const char  sz1[] = "http://www.abc.com";
const char* sz2   = "http://www.abc.com";

这已经足以使它成为不公平的测试。

szmatch是循环不变的,您应该将它们移动到之前(在这两种情况下都是sz)。

在第二种情况下sz是一个初始化的数组,而不是指向常量文字的指针 - 这是一个不公平和不必要的差异。 也就是说,如果按照建议将声明移动到循环之前,这应该几乎没有区别。

尽管regex_search()对于可能在内部导致构造std::string的常量const char*是重载的,但为了避免这种可能性,您应该使用以下方法进行测试:

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 {
}
}