Perl Regex意外的性能损失

rob*_*but 3 regex perl performance pcre

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;
                        }
                },
});
Run Code Online (Sandbox Code Playgroud)

结果 :

                                      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%             --
Run Code Online (Sandbox Code Playgroud)

因为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%             --
Run Code Online (Sandbox Code Playgroud)

因此,有两个问题可以总结:
-弦首锚为什么要减半性能?
-为什么将表达式(qr //)编译为变量比在行中使用相同的表达式要慢80%?

Dav*_*ell 5

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

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

  • 您能否详细说明其中的任何一个或提供链接?qr对象的“ _sinal刑罚_”不能解释OP显示此落后于其他相等匹配(我在测试中确认)的3(三)因数。另外,哪种优化方法可以帮助始终将_is_的模式的匹配锚定在字符串的开头(这是什么测试,而不是失败)? (2认同)