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

时间:2014-01-06 03:21:11

标签: c++ c regex

我与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&amp;的结果大约是2秒。 regex_match。这比C的regex.h库慢大约30倍。

我的比较有什么问题吗? C ++的正则表达式库不适用于高性能案例吗?

我可以理解它很慢,因为c ++的正则表达式库中没有优化,但是速度慢了30倍。

感谢。


大家好,

感谢您的回答。

对不起,我的错误是我也在使用[] C,但后来我改了,忘记更改C ++代码了。

我做了两处修改,

  1. 我将const char sz []移出了C&amp; C ++。
  2. 我用-O2编译它(之前我没有使用任何优化),C库的实现仍然是大约60毫秒,但是libc ++的正则表达式现在提供了一个数字,regex_search为1秒,regex_match为150毫秒。 / LI>

    这仍然有点慢,但没有原始比较那么多。

3 个答案:

答案 0 :(得分:11)

以下两行 not 做同样的事情!

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

这已经足以让它成为一个不公平的考验。

答案 1 :(得分:9)

如果您查看http://llvm.org/svn/llvm-project/libcxx/trunk/include/regex,您会看到此regex_match的实现位于regex_search之上,并且所有重载都会提取子表达式匹配位置,即使只是进入本地临时值扔掉了。 regex_search使用vector __state.resize()调用它们的对象,因此大概也是向量 - 当子表达式匹配时不需要所有堆分配和不必要,但是需要跟踪在正则表达式的perl样式扩展中支持\1等:旧的regcomp / regexec C函数没有提供那些额外的功能工作。当然,如果clang实现检查了正则表达式在编译期间跟踪匹配的需要并调用更精简,更快的函数以便在可能的情况下匹配,那将是很好的,但我想他们只是从支持一般情况开始。

答案 2 :(得分:1)

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

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

虽然const regex_search()的{​​{1}}重载可能会在内部造成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 {
    }
}