为什么使用qr预编译的正则数比使用常量正则表达式慢?

时间:2017-03-24 22:08:03

标签: perl

我刚看到this question关于优化Perl中的特定正则表达式。我想知道我的机器可以做多少匹配,所以我尝试了以下简单的基准测试:

  • 案例1 - 使用预编译的qr
  • 正则表达式
  • 案例2 - 普通/regex/匹配
use 5.014;
use warnings;

use Benchmark qw(:all);

my $str = "SDZ";
my $qr = qr/S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/;

say "match [$&]" if( $str =~ $qr );

my $res = timethese(-10, {
    stdrx => sub { $str =~ /S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/ },
    qr_rx => sub { $str =~ $qr },
});

cmpthese $res;

令我惊讶的是,它给出了以下结果:

match [SDZ]
Benchmark: running qr_rx, stdrx for at least 10 CPU seconds...
     qr_rx: 10 wallclock secs ( 9.99 usr +  0.01 sys = 10.00 CPU) @ 1089794.90/s (n=10897949)
     stdrx: 11 wallclock secs (10.58 usr +  0.04 sys = 10.62 CPU) @ 1651340.11/s (n=17537232)
           Rate qr_rx stdrx
qr_rx 1089795/s    --  -34%
stdrx 1651340/s   52%    --

即。普通$str =~ /regex/比使用$str =~ qr快约50%。我期待相反的结果。

我做错了吗?为什么我得到这个结果?

编辑:

只需downloaded引用的书,我有很多东西需要学习:)。但是,引用的书也说:

如果正则表达式文字没有变量插值,Perl知道正则表达式不能从使用变为使用,所以在正则表达式编译一次之后,保存(“缓存”)该编译表单,以便在执行再次达到相同代码时使用。无论在程序执行期间使用多长时间,都会对正则表达式进行一次检查和编译。

因此,在上面两个正则表达式都是 literal 而没有变量插值。因此,“预编译”正则表达式应该与普通版相同。在这个例子中,它慢了50%。

Ikegami解释了为什么$str =~ $qr更慢。 (老实说,“慢”不是正确的术语,因为我们谈论的是几微秒...... :))

但perl文档说:

  

模式预编译到内部表示中   qr()的时刻避免了每次重新编译模式的需要   匹配/ $ pat /尝试。

从一个普通的perl用户(“不是一些高级perl和尚”)的角度来看,这意味着:预编译你的模式 - 它会更快,但事实是 - 它有助于只有正则表达式包含一些“非静态”部分......

老实说,我仍然不完全理解这一点 - 但是得到了一本书并且要去学习。 :)也许在文档中还有一句话 - 可以帮助初学者在他们开始学习时不会误解qr

谢谢大家!

1 个答案:

答案 0 :(得分:4)

如果不进行插值,则在编译时编译正则表达式模式。 qr//运算符中的正则表达式和stdrx中的匹配运算符中的正则表达式都没有插值,因此两者都是在编译时编译的。

qr_rx测试中花费的额外30μs用于“编译”第三个正则表达式:qr_rx中匹配运算符中的一个。不要忘记$_ =~ $re$_ =~ m/$re/的缩写。现在,当整个模式由内插的预编译正则表达式组成时,实际上不会发生编译,因为该情况是专门处理的,但显然仍然需要一些时间来使匹配操作使用预编译的正则表达式。 (也许它需要克隆它?)