производительность регулярных выражений Java против C ++ 11 - PullRequest
0 голосов
/ 30 мая 2018

Я изучаю регулярные выражения в C ++ и Java.Поэтому я провел тест производительности на регулярных выражениях c ++ 11 и java с тем же выражением и без ввода.Странно, регулярное выражение Java быстрее, чем регулярное выражение C ++ 11.Что-то не так в моем коде?Пожалуйста, поправьте меня

Java-код:

import java.util.regex.*;

public class Main {
    private final static int MAX = 1_000_000;
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Pattern p = Pattern.compile("^[\\w._]+@\\w+\\.[a-zA-Z]+$");
        for (int i = 0; i < MAX; i++) {
            p.matcher("abcd_ed123.t12y@haha.com").matches();
        }
        long end = System.currentTimeMillis();
        System.out.print(end-start);
    }
}

C ++-код:

#include <iostream>
#include <Windows.h>
#include <regex>

using namespace std;

int main()
{
    long long start = GetTickCount64();
    regex pat("^[\\w._]+@\\w+\\.[a-zA-Z]+$");
    for (long i = 0; i < 1000000; i++) {
        regex_match("abcd_ed123.t12y@haha.com", pat);
    }
    long long end = GetTickCount64();
    cout << end - start;
    return 0;
}

Производительность:

Java -> 1003ms
C++  -> 124360ms

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Сделал образец C ++ переносимым:

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

using C = std::chrono::high_resolution_clock;
using namespace std::chrono_literals;

int main()
{
    auto start = C::now();
    std::regex pat("^[\\w._]+@\\w+\\.[a-zA-Z]+$");
    for (long i = 0; i < 1000000; i++) {
        regex_match("abcd_ed123.t12y@haha.com", pat);
    }
    std::cout << (C::now() - start)/1.0ms;
}

На Linux, а с clang++ -std=c++14 -march=native -O3 -o clang ./test.cpp я получаю 595.970 ms.См. Также Live On Wandbox

Java работает в 561 ms на той же машине.

Обновление : Boost Regex работает намного быстрее, см. Ниже сравнительный тест

Предупреждение : синтетические тесты, подобные этим, очень подвержены ошибкам:Компилятор может почувствовать, что не наблюдается никаких видимых побочных эффектов, и оптимизировать весь цикл, просто чтобы привести пример.

Больше удовольствия: добавление повышения к миксу

Использование Boost 1.67 и Платформа микро-бенчмаркинга Nonius

enter image description here

Мы можем видеть, что реализации Regex в Boost значительно быстрее.

См. подробные примеры интерактивных данных онлайн: https://plot.ly/~sehe/25/

Используемый код

#include <iostream>
#include <regex>
#include <boost/regex.hpp>
#include <boost/xpressive/xpressive_static.hpp>
#define NONIUS_RUNNER
#include <nonius/benchmark.h++>
#include <nonius/main.h++>

template <typename Re>
void test(Re const& re) {
    regex_match("abcd_ed123.t12y@haha.com", re);
}

static const std::regex std_normal("^[\\w._]+@\\w+\\.[a-zA-Z]+$");
static const std::regex std_optimized("^[\\w._]+@\\w+\\.[a-zA-Z]+$", std::regex::ECMAScript | std::regex::optimize);
static const boost::regex boost_normal("^[\\w._]+@\\w+\\.[a-zA-Z]+$");
static const boost::regex boost_optimized("^[\\w._]+@\\w+\\.[a-zA-Z]+$", static_cast<boost::regex::flag_type>(boost::regex::ECMAScript | boost::regex::optimize));

static const auto boost_xpressive = []{
    using namespace boost::xpressive;
    return cregex { bos >> +(_w | '.' | '_') >> '@' >> +_w >> '.' >> +alpha >> eos };
}();

NONIUS_BENCHMARK("std_normal",      [] { test(std_normal);      })
NONIUS_BENCHMARK("std_optimized",   [] { test(std_optimized);   })
NONIUS_BENCHMARK("boost_normal",    [] { test(boost_normal);    })
NONIUS_BENCHMARK("boost_optimized", [] { test(boost_optimized); })
NONIUS_BENCHMARK("boost_xpressive", [] { test(boost_xpressive); })

Примечание Вот выходные данные JIT-компилятора Hotspot:

Это было сгенерировано с помощью

LD_PRELOAD = / home / sehe / Projects / stackoverflow / fcml-1.1.3 / example / hsdis / .libs / libhsdis-amd64.so ./jre1.8.0_171/bin/java -XX: + UnlockDiagnosticVMOptions -XX: + PrintAssembly Main 2> & 1> disasm.a

0 голосов
/ 30 мая 2018

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

Да, C ++ 11 std::regex немного медленнее (даже в режиме Release), чем Java.

Но PCRE2 с JIT работает в 3 раза быстрее:

#include <iostream>
#include <chrono>
#define PCRE2_STATIC
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"

using namespace std;
using namespace std::chrono;
using namespace std::chrono_literals;

int main()
{
    auto start = high_resolution_clock::now();
    int errn;
    PCRE2_SIZE erroffset;
    auto pattern = (PCRE2_SPTR8)"^[\\w._]+@\\w+\\.[a-zA-Z]+$";
    pcre2_code* re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errn, &erroffset, nullptr);
    if (!re)
        cerr << "pcre2_compile failed\n";
    pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(re, nullptr);
    for (long i = 0; i < 1000000; i++) {
        auto text = (PCRE2_SPTR8)"abcd_ed123.t12y@haha.com";
        int rc = pcre2_match(re, text, PCRE2_ZERO_TERMINATED, 0, 0, match_data, nullptr);
        if (rc <= 0)
            cerr << "pcre2_match failed\n";
    }
    auto end = high_resolution_clock::now();
    cout << (end - start) / 1ms << "\n";
    return 0;
}

Результаты:

  • PCRE2 v10.21: 139ms
  • Java: 440ms
0 голосов
/ 30 мая 2018

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

Поскольку вы используете VisualВ Studio 2017 найдите раскрывающийся список «Конфигурация решения» и измените его с Debug на Release.

screenshot of Visual Studio 2017

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...