Erlang regex re performance - PullRequest
       4

Erlang regex re performance

0 голосов
/ 22 февраля 2019

Попытка некоторых тестов производительности регулярных выражений (слышал некоторые слухи, что erlang работает медленно)

>Fun = fun F(X) -> case X > 1000000 of true -> ok; false -> Y = X + 1, re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, "^[a-zA-Z0-9_]+$"), F(Y) end end.
#Fun<erl_eval.30.128620087>
> timer:tc(Fun, [0]).                                                         
{17233982,ok}                                                                   
> timer:tc(Fun, [0]).   
{17155982,ok}

и некоторые тесты после компиляции регулярных выражений

{ok, MP} = re:compile("^[a-zA-Z0-9_]+$").                                   
{ok,{re_pattern,0,0,0,                                                          
            <<69,82,67,80,107,0,0,0,16,0,0,0,1,0,0,0,255,255,255,
              255,255,255,...>>}}
> Fun = fun F(X) -> case X > 1000000 of true -> ok; false -> Y = X + 1, re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, MP), F(Y) end end.               
#Fun<erl_eval.30.128620087>
> timer:tc(Fun, [0]).                                                         
{15796985,ok}                                                                   
>        
> timer:tc(Fun, [0]).
{15921984,ok}

http://erlang.org/doc/man/timer.html:

Если не указано иное, время всегда измеряется в миллисекундах.

http://erlang.org/doc/man/re.html#compile-1:

Компиляция регулярного выражения перед сопоставлениемполезно, если одно и то же выражение должно использоваться при сопоставлении с несколькими предметами в течение всей жизни программы.Компиляция один раз и многократное выполнение гораздо эффективнее, чем компиляция каждый раз, когда нужно найти соответствие.

Вопросы

  1. Почему он возвращает микросекунды вменя? (должно быть в миллисекундах?)
  2. Компиляция регулярных выражений не имеет большого значения, почему?
  3. Должен ли я беспокоиться о его компиляции?

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Да, вы должны скомпилировать код, прежде чем пытаться измерить производительность.Когда вы вводите код в оболочку, код будет интерпретирован, а не скомпилирован в байт-код.Я увидел большое улучшение при помещении кода в модуль:

7> timer:tc(Fun, [0]).
{6253194,ok}
8> timer:tc(fun foo:run/1, [0]).
{1768831,ok}

(оба скомпилированных регулярных выражений.)

-module(foo).

-compile(export_all).

run(X) ->
    {ok, MP} = re:compile("^[a-zA-Z0-9_]+$"),
    run(X, MP).

run(X, _MP) when X > 1000000 ->
    ok;
run(X, MP) ->
    Y = X + 1,
    re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, MP),
    run(Y).
0 голосов
/ 22 февраля 2019
  1. В модуле таймер функция tc / 2 возвращает микросекунды
tc(Fun) -> {Time, Value}
tc(Fun, Arguments) -> {Time, Value}
tc(Module, Function, Arguments) -> {Time, Value}
    Types
    Module = module()
    Function = atom()
    Arguments = [term()]
    Time = integer()
      In microseconds
    Value = term()
Поскольку функция Fun должна компилировать строку "^[a-zA-Z0-9_]+$" каждую рекурсивную (1 миллион раз) в случае 1. В отличие от этого, сначала вы выполняете компиляцию в случае 2. После этого вы переносите результат в рекурсивнуюЭто и есть причина, по которой производительность ниже, чем в случае 1.

run (Subject, RE) -> {match, Captured} |nomatch

Subject = iodata () |Юникод: charlist ()

RE = mp () |iodata ()

Регулярное выражение может быть указано либо как iodata (), в этом случае оно автоматически компилируется (как compile / 2) и выполняется, либо как предварительно скомпилированное mp (), в этом случае оно выполняетсяпротив субъекта напрямую.

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