我刚看到this question关于优化Perl中的特定正则表达式。我想知道我的机器可以做多少匹配,所以我尝试了以下简单的基准测试:
qr
/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
。
谢谢大家!
答案 0 :(得分:4)
如果不进行插值,则在编译时编译正则表达式模式。 qr//
运算符中的正则表达式和stdrx
中的匹配运算符中的正则表达式都没有插值,因此两者都是在编译时编译的。
在qr_rx
测试中花费的额外30μs用于“编译”第三个正则表达式:qr_rx
中匹配运算符中的一个。不要忘记$_ =~ $re
是$_ =~ m/$re/
的缩写。现在,当整个模式由内插的预编译正则表达式组成时,实际上不会发生编译,因为该情况是专门处理的,但显然仍然需要一些时间来使匹配操作使用预编译的正则表达式。 (也许它需要克隆它?)