bri*_*foy 11

执行摘要:使用5.010的/ p代替.$&对于单个匹配或替换,性能大致相同,但整个程序可能会受到影响.它的减速是远程的,而不是局部的.


这是5.010的基准测试,我怀疑你使用它是因为你say在那里.请注意,5.010有一个新/p标志,它提供一个${^MATCH}变量,其作用类似于$&匹配或替换运算符的一个实例.

与任何基准测试一样,我与控件进行比较以设置基线,因此我知道无聊位需要多长时间.此外,此基准测试还有一个陷阱:您无法$&在代码中使用或每次替换都会受到影响.首先运行没有$&sub 的基准:

use 5.010;

use Benchmark qw(cmpthese);

cmpthese(1_000_000, {
   'control' => sub { my $_ = 'abc123def'; s/\d+/246/ },
   'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e;  },
   '/p'      => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe },
   # '$&'      => sub { my $_ = 'abc123def'; s/\d+/$&*2/e },
   '()'      => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e },
});
Run Code Online (Sandbox Code Playgroud)

在我的MacBook Air上运行Leopard和一个vanilla Perl 5.10:

              Rate        /p        () control-e   control
/p         70621/s        --       -1%      -58%      -78%
()         71124/s        1%        --      -58%      -78%
control-e 168350/s      138%      137%        --      -48%
control   322581/s      357%      354%       92%        --
Run Code Online (Sandbox Code Playgroud)

请注意/e选项的大幅减速,我只是为咯咯笑而添加.

现在,我将取消对$&分支的注释,我发现一切/p都比较慢,尽管似乎在这里:

              Rate        ()        $&        /p control-e   control
()         68353/s        --       -4%       -7%      -58%      -74%
$&         70872/s        4%        --       -3%      -56%      -73%
/p         73421/s        7%        4%        --      -54%      -72%
control-e 161290/s      136%      128%      120%        --      -39%
control   262467/s      284%      270%      257%       63%        --
Run Code Online (Sandbox Code Playgroud)

这是一个奇怪的基准.如果我不包括control-esub,则情况看起来不同,这表明了基准测试的另一个概念:它不是绝对的,并且您在最终结果中所做的一切都很重要.在这次运行中,$&看起来略快一些:

            Rate      ()      /p      $& control
()       69686/s      --     -3%     -3%    -72%
/p       72098/s      3%      --     -0%    -71%
$&       72150/s      4%      0%      --    -71%
control 251256/s    261%    248%    248%      --
Run Code Online (Sandbox Code Playgroud)

所以,我control-e再次运行它,结果移动了一点:

              Rate        ()        /p        $& control-e   control
()         68306/s        --       -3%       -4%      -55%      -74%
/p         70175/s        3%        --       -1%      -54%      -73%
$&         71023/s        4%        1%        --      -53%      -73%
control-e 151976/s      122%      117%      114%        --      -41%
control   258398/s      278%      268%      264%       70%        --
Run Code Online (Sandbox Code Playgroud)

每个人的速度差异也不令人印象深刻.任何低于7%的东西都不是那么重要,因为这种差异是通过重复调用sub来累积错误(有时通过对相同的代码进行基准测试来尝试它).您看到的细微差别仅来自基准测试基础架构.有了这些数字,每种技术在速度上几乎都是相同的.你不能只运行一次基准测试.你必须多次运行它,看看你是否得到了可重复的结果.

请注意,虽然/p看起来非常慢,但它也会因为$&欺骗每个人而作弊.注意控制中的减速也是如此.这是基准测试如此危险的原因之一.如果你不认真思考它们为什么是错误的话,你很容易误导自己的结果(参见Mastering Perl中的完整熨平板,我在这里用了整整一章.)

然而,这个简单而天真的基准排除了杀手的贬低$&.让我们修改基准来处理额外的匹配.首先,基线没有$&效果,我构建了一个$&必须在另一个匹配运算符中复制大约1,000个字符的情况:

use 5.010;

use Benchmark qw(cmpthese);

$main::long = ( 'a' x 1_000 ) . '123' . ( 'b' x 1_000 );

cmpthese(1_000_000, {
   'control' => sub { my $_ = 'abc123def'; s/\d+/246/; $main::long =~ m/^a+123/; },
   'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e; $main::long =~ m/^a+123/; },
   '/p'      => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe; $main::long =~ m/^a+123/; },
   #'$&'      => sub { my $_ = 'abc123def'; s/\d+/$&*2/e; $main::long =~ m/^a+123/;},
   '()'      => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e; $main::long =~ m/^a+123/; },
});
Run Code Online (Sandbox Code Playgroud)

一切都比以前慢得多,但这就是当你做更多的工作时会发生的事情,而且这两种技术在彼此的噪音之内:

              Rate        ()        /p control-e   control
()         52826/s        --       -4%      -49%      -63%
/p         54885/s        4%        --      -47%      -61%
control-e 103734/s       96%       89%        --      -27%
control   141243/s      167%      157%       36%        --
Run Code Online (Sandbox Code Playgroud)

现在,我取消注释$&子:

              Rate        ()        $&        /p control-e   control
()         50607/s        --       -1%       -3%      -43%      -59%
$&         50968/s        1%        --       -2%      -43%      -58%
/p         52274/s        3%        3%        --      -41%      -57%
control-e  89206/s       76%       75%       71%        --      -27%
control   122100/s      141%      140%      134%       37%        --
Run Code Online (Sandbox Code Playgroud)

结果非常有趣.现在/p,仍然受到作弊的惩罚$&,虽然每个人都受到严重影响,但速度稍快(虽然仍在噪音范围内).

再次,要非常小心这些结果.这并不意味着每个脚本$&都会产生相同的效果.您可能看起来不那么慢,或者更多,这取决于匹配的数量,特定的正则表达式等等.这个或任何基准测试显示的是一个想法,而不是一个决定.您仍然需要弄清楚这个想法如何影响您的特定情况.


Chr*_*utz 10

来自perldoc perlvar:

  • $ MATCH
  • $&

与上一次成功模式匹配的字符串匹配(不计算隐藏在当前内容中BLOCKeval()由当前包含的任何匹配BLOCK).(助记符:喜欢&在某些编辑器中.)此变量是只读的,并且动态范围限定为当前变量BLOCK.

在程序中的任何位置使用此变量会对所有正则表达式匹配造成相当大的性能损失.见"BUGS".

请参阅"@-"替换.

即使这些信息在文档中不方便,您仍然可以自己计时并找出答案.

  • 尽管对每个实例的成千上万个实例的天真测试似乎表明`$&'比分组略快.但是,正如文档所说,使用`$&`_at all_使_all_ regexes变慢,而使用括号只会减慢使用括号的正则表达式. (6认同)