【问题标题】:Regex speed in Perl 6Perl 6 中的正则表达式速度
【发布时间】:2018-04-02 16:40:09
【问题描述】:

我以前只使用bash 正则表达式、grepsedawk 等。在尝试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;

然后我将@array打印到一个名为array的文件中(有7776行),用3行(abcdecdefffabcd)创建了一个名为search的文件并做了一个简单的@ 987654337@搜索。

$ grep -f search array

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

$ 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

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

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

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

my @search = <abcde cdeff fabcd>;

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

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

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

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

【问题讨论】:

    标签: raku


    【解决方案1】:

    grep 命令比 Perl 6 的正则表达式要简单得多,而且它还有很多年才能得到优化。这也是 Rakudo 中没有进行太多优化的领域之一;部分原因是它被认为是一件很难做的事情。


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

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

    该更改导致它在大约半秒内运行。

    如果@search中存在任何恶意数据的可能性,并且您必须这样做,那么使用它可能会更安全:

    "/@search».Str».perl.join('|')/".EVAL
    

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

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

    【讨论】:

    • 感谢您的解决方案和解释!它与.join 一起工作确实非常快(但比bash 中的gnu grep 慢得多)!我能否请您澄清以下内容? ①我说得对吗,主要浪费时间是因为程序每次要与@array的元素进行比较时都会检查@search的值? ②».语法是什么意思,应该注意什么类型的恶意代码?在我的工作中,搜索的键可能来自带有数据的文件,所以事先检查它们会很好吗?
    • regex 机器在 Perl 5 中是否运行得更快,那么我们是否希望将来在 Perl 6 中它会更快? ④我不完全理解你最后的陈述(关于子语言),所以你能解释一下吗?我觉得这是一件很重要的事情。 ⑤ 如果我需要执行非常繁重(具有非常大的数据或非常多的搜索键)但简单的regex 操作,是否有其他方法可以优化 Perl 6 的性能,或者我宁愿使用简单的bash 脚本来处理它们?
    • @evb ① 大部分是的 ② @foo».bar 类似于@foo.map(*.bar)。 ③Perl 5 中的正则表达式明显不同④ 在大多数语言中,正则表达式是一个单独的东西,可以单独编译,在 Perl 6 中,它只是具有不同语法的代码。 ⑥ 您可以并行化这些操作以使用尽可能多的 CPU 内核。另外,正如我所说,它只是代码,您可以优化代码,是的,可能有一些方法可以编写更优化的版本。
    • 又一个问题(我应该把它作为一个单独的 Q 发布吗?)我的搜索键通常是arrays 中提供的所有可能的(连接的)原子组合,所以我想知道它是否是有没有可能为了提高性能预编译一个regex,它本身由几个名为regexes的?那么是否可以在语法中预编译TOPregex/token? (当然我明白,如果组合太多,结果可能会放不下内存)
    • 如果你使用常量字符串和 eq:say ~@array.grep({ $^a eq "abcde" or $^a eq "cdeff" or $^a eq "fabcd" }) 只需要 0.24 秒(其中 0.09 秒是启动和编译),你会有更好的性能
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多