Perl Regex: неожиданный удар по производительности - PullRequest
3 голосов
/ 20 июня 2019

Perl v5.28.1

Тест:

use common::sense;
use Benchmark qw(:all);

my $UPPER = 10_000_000;
my $str = 'foo bar baz';

cmpthese(10, {
        'empty for-loop' => sub {
                        for my $i (1..$UPPER) {}
                },
        'regex match' => sub {
                        for my $i (1..$UPPER) {
                                $str =~ /foo/;
                        }
                },
        'regex match (single compile)' => sub {
                        my $re = qr/foo/;
                        for my $i (1..$UPPER) {
                                $str =~ $re;
                        }
                },
        'regex match (anchor)' => sub {
                        for my $i (1..$UPPER) {
                                $str =~ /^foo/;
                        }
                },
        'regex match (anchor) (single compile)' => sub {
                        my $re = qr/^foo/;
                        for my $i (1..$UPPER) {
                                $str =~ $re;
                        }
                },
});

Результаты:

                                      s/iter regex match (anchor) (single compile) regex match (single compile) regex match (anchor) regex match empty for-loop
regex match (anchor) (single compile)   3.83                                    --                         -21%                 -60%        -84%           -97%
regex match (single compile)            3.04                                   26%                           --                 -50%        -80%           -96%
regex match (anchor)                    1.53                                  151%                          99%                   --        -61%           -92%
regex match                            0.601                                  537%                         405%                 154%          --           -81%
empty for-loop                         0.117                                 3170%                        2496%                1205%        414%             --

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

Кроме того, я читал кое-что о том, что Perl достаточно умен, чтобы не перекомпилировал выражения с фиксированными строками, даже если они содержатся внутри циклов.
Но почему попытка вручную / явно «прекомпилировать» выражение в переменную $ re может привести к такому падению производительности ?!

Я изменил подстроку поиска "foo" на "asdf" (чего не происходит в $ str), и привязка позволяет движку быстрее прекращать поиск. Но назначение выражения в переменную все еще является огромным ударом по производительности - гораздо больше, чем я ожидал! :

                                         Rate regex match (single compile) regex match (anchor) (single compile) regex match regex match (anchor) empty for-loop
regex match (single compile)          0.401/s                           --                                  -10%        -79%                 -83%           -96%
regex match (anchor) (single compile) 0.447/s                          11%                                    --        -76%                 -81%           -95%
regex match                            1.88/s                         369%                                  321%          --                 -19%           -79%
regex match (anchor)                   2.33/s                         481%                                  421%         24%                   --           -75%
empty for-loop                         9.17/s                        2185%                                 1951%        387%                 294%             --

Итак, 2 вопроса для подведения итогов:
- Почему производительность якоря в начале строки должна быть в два раза меньше?
- Почему компиляция выражения (qr //) в переменную должна быть на 80% медленнее, чем при использовании одного и того же выражения в строке?

1 Ответ

5 голосов
/ 20 июня 2019

Добавление привязки препятствовало определенной оптимизации регулярных выражений.Это было исправлено в 5.30.0.

Использование объекта qr // в настоящее время влечет за собой небольшое наказание, поскольку внутренняя часть структуры регулярного выражения должна быть скопирована (в связи с тем, что каждый объект регулярного выражения имеет свой собственныйнабор индексов захвата).Никто еще не придумал, как это исправить.

...