Perl Regex意外的性能损失

时间:2019-06-20 18:58:50

标签: regex performance perl pcre

Perl v5.28.1

基准:

let my_array = [34, 44, 72];

axios.post(
    'url-to-get-data',
    {
        post_data_1: my_array[0]
    }
    ).then(res => {
        axios.post(
            'url-to-get-data',
            {
                post_data_1: my_array[1],
                post_data_2: res.data
            }
            ).then(res => {
                 //Third axios post.....
            }
            ).catch();
        }
        ).catch();

结果:

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;
                        }
                },
});

由于foo恰好发生在字符串的开头,我希望在正则表达式中添加一个显式锚(^)不会执行任何操作……不会使性能减半!

同样,我读到一些东西,使Perl足够聪明,即使包含在循环中,也可以用固定的字符串重新编译表达式。
但是,为什么尝试手动/明确地将表达式“预编译”为变量$ re会导致性能下降呢?

我将搜索子字符串“ foo”更改为“ asdf”(在$ str中不出现),锚定的确使引擎退出了更快的搜索范围。 但是,将表达式分配给变量仍然会严重影响性能-比我预期的要好得多! :

                                      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%             --

所以要总结两个问题:
 -为什么弦首锚会使演奏减半?
 -为什么将表达式(qr //)编译为变量比在行中使用相同的表达式要慢80%?

1 个答案:

答案 0 :(得分:5)

添加锚点可防止发生特定的正则表达式优化。此问题已在5.30.0中修复。

由于必须复制内部正则表达式结构的一部分(与每个正则表达式对象都有其自己的捕获索引这一事实有关),因此使用qr //对象当前会产生轻微的损失。到目前为止,还没有人想到一个好的解决方案。