2014-01-06 4 views
7

I по сравнению с библиотекой регулярных выражений Linux C,Почему C++ 11 regex (реализация libC++) настолько медленная?

#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; 
} 

В результате примерно 2 секунды для обоих regex_search & алгоритма regex_match. Это примерно в 30 раз медленнее, чем в библиотеке regex.h.

Есть ли что-то не так с моим сравнением? Является ли библиотека регулярных выражений C++ не подходящей для случая высокой производительности?

Я могу понять, что он медленный, потому что в библиотеке регулярных выражений C++ нет оптимизации, но в 30 раз медленнее это слишком много.

Спасибо.


Привет всем,

Спасибо за ответы.

Извините за свою ошибку. Я использовал [] для C, но позже я изменил и забыл изменить код на C++.

Я сделал два изменения,

  1. я переехал сопзЬ символ SZ [] из петли как для C & C++.
  2. Я скомпилировал его с -O2 (раньше я не использовал какую-либо оптимизацию), реализация библиотеки C по-прежнему составляет около 60 миллисекунд, но теперь регулярное выражение libC++ дает число: 1 секунда для regex_search и 150 миллисекунд для regex_match.

Это все еще немного медленно, но не так, как оригинальное сравнение.

+0

Ну, во-вторых, вы копируете массив символов каждый раз, если только он не оптимизирован (вряд ли без оптимизации). Во-первых, вы просто указываете на что-то. Вы также должны построить 'std :: string' для вызовов во втором. – chris

+0

Версия компилятора? Точный выход? –

+2

В прошлый раз, когда я пытался, реализация libge ++ regex была действительно медленной, проверьте этот вопрос для сравнения с boost :: regex и python: http://stackoverflow.com/questions/14205096 –

ответ

8

Если вы посмотрите на http://llvm.org/svn/llvm-project/libcxx/trunk/include/regex вы увидите это реализация regex_match наслаивается на вершине regex_search, и все перегруженные извлечь матч подвыражении позиции, даже если только на локальные временные ресурсы, которые выбрасываются. regex_search использует из __state объектов, которые имеют на них .resize(), так что предположительно векторы тоже - все распределения кучи и ненужные, когда совпадения подвыражений не нужны, но их необходимо отслеживать для поддержки \1 и т. Д. В расширениях в стиле perl для регулярных выражения: старые regcomp/regexec Функции C не предусматривали, что эти расширенные функции никогда не должны выполнять эту дополнительную работу. Конечно, было бы неплохо, если бы реализация clang проверила необходимость регулярного выражения для отслеживания совпадений во время компиляции и назвала бы более быстрые, более быстрые функции, если это возможно, но, я думаю, они только начинают с поддержки общего случая.

+0

Спасибо. Это хорошее объяснение. – user534498

10

Следующие две строки делают не сделать то же самое!

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

Этого уже достаточно, чтобы сделать его несправедливым.

+0

указанный код должен быть исправлен, чтобы иметь смысл –

+0

@pepper_chico: Вы что теперь? –

+0

'const char * =" http://www.abc.com ";' не компилируется, и это не оригинальный код. только то. –

1

sz и match являются инвариантами цикла, вы должны перенести их до (в обоих случаях для sz).

Во втором случае sz является инициализированным массивом вместо указателя на постоянный литерал - это несправедливая и ненужная разница. Тем не менее, если вы перемещаете декларацию до цикла, как это было предложено, это должно незначительно отличаться.

Хотя regex_search() перегружен для сопзЬ 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 { 
    } 
} 
+0

Привет, спасибо. Первый исправлен. Второй (изменение от const char * до std :: string), похоже, не оказывает никакого влияния на результат (для regex_search и regex_match). – user534498

Смежные вопросы