Perl 6中的正则表达速度

Eug*_*sky 5 perl6

我以前只工作bash正则表达式grep,sed,awk等努力后,Perl 6 regexes我有一个印象,即他们的工作慢于我所期望的,但可能的原因是,我处理这些错误.我做了一个简单的测试,以比较类似的操作Perl 6bash.这是Perl 6代码:

my @array = "aaaaa" .. "fffff";
say +@array; # 7776 = 6 ** 5

my @search = <abcde cdeff fabcd>;

my token search {
    @search
}

my @new_array = @array.grep({/ <search> /});
say @new_array;
Run Code Online (Sandbox Code Playgroud)

然后我印刷@array到一个命名的文件array(具有7776线),由指定的文件search具有3条线(abcde,cdeff,fabcd),并提出了简单的grep搜索.

$ grep -f search array
Run Code Online (Sandbox Code Playgroud)

在两个程序产生与预期相同的结果后,我测量了他们工作的时间.

$ time perl6 search.p6
real    0m6,683s
user    0m6,724s
sys     0m0,044s
$ time grep -f search array
real    0m0,009s
user    0m0,008s
sys     0m0,000s
Run Code Online (Sandbox Code Playgroud)

那么,我在Perl 6代码中做错了什么?

UPD:如果我将搜索标记传递给grep循环@search数组,程序运行得更快:

my @array = "aaaaa" .. "fffff";
say +@array;

my @search = <abcde cdeff fabcd>;

for @search -> $token {
  say ~@array.grep({/$token/});
}
Run Code Online (Sandbox Code Playgroud)
$ time perl6 search.p6
real    0m1,378s
user    0m1,400s
sys     0m0,052s
Run Code Online (Sandbox Code Playgroud)

如果我手动定义每个搜索模式,它的工作速度会更快:

my @array = "aaaaa" .. "fffff";
say +@array; # 7776 = 6 ** 5

say ~@array.grep({/abcde/});
say ~@array.grep({/cdeff/});
say ~@array.grep({/fabcd/});
Run Code Online (Sandbox Code Playgroud)
$ time perl6 search.p6
real    0m0,587s
user    0m0,632s
sys     0m0,036s
Run Code Online (Sandbox Code Playgroud)

Bra*_*ert 8

grep 命令比Perl 6的正则表达式简单得多,而且它还有很多年的优化时间.它也是在Rakudo中没有看到太多优化的领域之一; 部分原因是它被认为是一件难以开展工作的事情.


对于更高性能的示例,您可以预编译正则表达式:

my $search = "/@search.join('|')/".EVAL;
#  $search =  /abcde|cdeff|fabcd/;
say ~@array.grep($search);
Run Code Online (Sandbox Code Playgroud)

这种变化导致它在大约半秒内运行.

如果有任何恶意数据的可能性@search,您必须这样做,使用起来可能更安全:

"/@search».Str».perl.join('|')/".EVAL
Run Code Online (Sandbox Code Playgroud)

编译器无法完全生成优化代码,/@search/因为@search在编译正则表达式后可能会发生变化.可能发生的情况是,第一次使用正则表达式时,它会被重新编译为更好的形式,然后只要@search不进行修改就缓存它.
(我认为Perl 5做了类似的事情)

您必须记住的一个重要事实是,Perl 6中的正则表达式只是一种用特定于域的子语言编写的方法.

  • 如果你使用常量字符串和eq:'say~@array.grep({$ ^ a eq"abcde"或$ ^ a eq"cdeff"或$ ^ a eq"fabcd"},你的表现仍会好得多)`仅需0.24s(其中0.09s是启动和编译) (2认同)