为什么 C++11 正则表达式(libc ++ 实现)如此缓慢?
why c++11 regex (libc++ implementation) is so slow?
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++代码。
我做了两个更改,
- 我将 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
,这些对象.resize()
调用它们,所以大概也是向量 - 当不需要子表达式匹配时,所有堆分配和不必要的,但需要跟踪以支持正则表达式的perl样式扩展中的1
等:旧的regcomp
/regexec
C函数没有提供那些扩展功能,永远不必做这些额外的工作。 当然,如果 clang 实现在编译期间检查正则表达式对跟踪匹配的需求并在可能的情况下调用更精简、更快的函数进行匹配,那就太好了,但我想他们只是从支持一般情况开始。
以下两行不做同样的事情!
const char sz1[] = "http://www.abc.com";
const char* sz2 = "http://www.abc.com";
这已经足以使它成为不公平的测试。
sz
和match
是循环不变的,您应该将它们移动到之前(在这两种情况下都是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 {
}
}
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- 为什么 C++11 正则表达式(libc ++ 实现)如此缓慢?