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 恰好出现在字符串的开头,所以我希望在正则表达式中添加一个显式 anchor (^) 什么都不做……不会使性能减半!

同样,我读过一些内容,大意是 Perl 足够聪明,即使包含在循环中,也不会重新编译带有固定字符串的表达式。
但是为什么尝试手动/明确地将表达式“预编译”为变量 $re 会导致这样的性能下降?!

我将搜索子字符串“foo”更改为“asdf”(它不会出现在 $str 中),并且 anchor 定确实让引擎更快地退出搜索。
但是将表达式分配给变量仍然是一个巨大的性能损失 - 比我预期的要多得多! :
                                         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%             --

所以要总结两个问题:
- 为什么开始的字符串 anchor 性能减半?
- 为什么将表达式 (qr//) 编译成变量比使用相同的内嵌表达式慢 80%?

最佳答案

添加 anchor 会阻止发生特定的正则表达式优化。这已在 5.30.0 中修复。

使用 qr//对象目前会产生轻微的惩罚,因为必须复制正则表达式结构的内部部分(与每个正则表达式对象都有自己的一组捕获索引这一事实有关)。没有人想到一个好的解决办法。

关于regex - Perl 正则表达式意外的性能命中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56692304/

10-16 11:44
查看更多