Performance 在perl中检查$string是否以$pinder开头的最有效方法

Performance 在perl中检查$string是否以$pinder开头的最有效方法,performance,perl,string-matching,Performance,Perl,String Matching,给定perl中的两个字符串变量$string和$pineel,检查$string是否以$pineel开头的最有效方法是什么 $string=~/^\Q$needle\E/是我能想到的最接近的匹配,它做了我所需要的,但是我尝试过的解决方案中效率最低的(到目前为止) 索引($string,$needle)==0工作,对于$string和$needle的某些值相对有效,但不需要在其他位置搜索指针(如果在开始时未找到) substr($string,0,length($needle))eq$needl

给定
perl
中的两个字符串变量
$string
$pineel
,检查
$string
是否以
$pineel
开头的最有效方法是什么

  • $string=~/^\Q$needle\E/
    是我能想到的最接近的匹配,它做了我所需要的,但是我尝试过的解决方案中效率最低的(到目前为止)
  • 索引($string,$needle)==0
    工作,对于
    $string
    $needle
    的某些值相对有效,但不需要在其他位置搜索指针(如果在开始时未找到)
  • substr($string,0,length($needle))eq$needle
    应该非常简单有效,但在我的大多数测试中,效率并不比前一个测试高
perl
中是否有一种我不知道的标准方法来实现这一点,或者是否有任何方法来优化上述任何解决方案

(在我的特定用例中,
$string
$needle
在每次运行中都会有所不同,因此预编译regexp不是一个选项)


如何测量给定解决方案的性能示例(此处来自POSIX
sh
):


事实正好相反。

这有多重要,真的吗?我做了很多基准测试,而
索引
方法平均每次迭代0.68微秒;regex法1.14μs;
substr
方法为0.16μs。即使是我最坏的情况(2250个相等的字符串),
index
也需要2.4μs,regex需要5.7μs,
substr
需要0.5μs

我的建议是编写一个库例程:

sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}
并将优化工作集中在其他地方

更新:基于对上述“最坏情况”场景的批评,我使用一个20000字符随机生成的字符串运行了一组新的基准测试,将其与自身和仅在最后一个字节中不同的字符串进行比较

对于如此长的字符串,regex解决方案是迄今为止最糟糕的(20000个字符的regex是地狱):匹配成功为105μs,匹配失败为100μs

index
substr
解决方案仍然相当快<成功/失败的代码>指数为11.83μs/11.86μs,
substr
为4.09μs/4.15μs。将代码移动到一个单独的函数会增加约0.222±0.05μs

基准代码可从以下网址获得:


我不知道@Stephane数据的特征,但我的建议是正确的。

另一个选项是将位置设置为0,这意味着“从不同版本的Perl开始,在$str中获取$substr的索引将在这里产生影响,我建议添加用于反馈或重用的基准代码。@Ashley,这一点很好,更新。也许您将编写
String::MoreUtils::XS
?您是否分析了脚本以确认确实需要此微优化?仅供参考,您应该在任何时候使用Perl进行基准测试
/usr/bin/time
不一定会给你一个公平的比较。对于早期的
perl
s,你可能会想要。不是没用,@ikegami。我的基准测试案例中有一半是匹配,一半是匹配失败。@SueD.nyme:您发布的答案的措辞暗示您的最坏情况测试只是匹配字符串。显然,
索引的最坏情况是一个非常长的干草堆,任何地方都没有针,因此它必须检查到底。不过,我同意你的结论:只要使用
substr
,因为我们已经证明,在普通情况下,它并不慢。它应该有一个更好的最坏情况,这对于抵御DOS攻击(或意外减速)很重要。与其简单地忽略我的基准测试结果,不如尝试复制它们。@PeterCordes,在字符串中找不到指针的情况下,有些情况比其他情况更糟糕,如问题中的最后一个示例,对于长度为34的字符串和长度为6的指针,至少需要111个字节到字节的比较((6+5+4+3+2+1)*5+6)。(这甚至可能是这种长度的线/针的最坏情况,这将引出另一个有趣的问题)非常感谢。这是我不知道也一直在寻找的功能。在这个问题中,我得到了两个测试用例的相似计时,并且它比这两个测试用例上的任何其他方法都要快。
string="aaaaabaaaaabaaaaabaaaaabaaaaabaaaaab" needle="aaaaaa"
sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}
> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1