【发布时间】:2017-03-24 22:08:02
【问题描述】:
我刚刚看到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。
谢谢大家!
【问题讨论】:
-
您为什么期望
qr更快?另外,如果您从程序中删除$&,会发生什么变化吗? -
@melpomene 因为文档说:在 qr() 时刻将模式预编译为内部表示避免了每次尝试匹配 /$pat/ 时都需要重新编译模式. 我的理解是:编译需要更多的处理,所以它必须更慢。 (看起来那是无效的)。 (删除
$&没有任何变化) -
但是您的代码中没有
/$pat/。您所有的正则表达式都是静态的,没有变量插值。qr在这里给您的唯一内容是间接级别,因为在匹配点它必须获取$qr的内容并测试它是正则表达式对象还是字符串,而=~ /.../将正则表达式存储为部分比赛操作。 -
您好。我启动了您引用的线程。我在
qr中使用命名正则表达式引用的原因是因为该正则表达式在程序中的多个位置使用。它有助于避免拼写错误以及与其他一些外观相似的正则表达式混淆,以查看$valid_steno而不是另一个冗长的正则表达式,抛开性能问题。 -
Re "在示例中,它慢了 50%。",不完全是。它慢了一个恒定的量。
标签: perl