每次我下载Rakudo Perl 6的新副本时,我都会运行以下表达式,以了解其当前的性能:

say [+] 1 .. 100000;

速度一直在增加,但是每次都有明显的延迟(几秒钟)。作为比较,Perl 5(或其他解释的语言)中类似的东西几乎立即返回:

use List::Util 'sum';

print sum(1 .. 100000), "\n";

或在红宝石中(也几乎瞬间):

(1 .. 100000).inject(0) {|sum,x| sum+x}

将表达式重写为perl6 loop 最终的速度大约是减少范围的两倍,但对于简单的计算,它仍然是一个非常明显的延迟(超过一秒钟):

my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}

因此,我的问题是,PERL6实施的哪些方面引起了这些绩效问题?这应该随着时间的推移而改善,还是这是perl6正在使用的“一切都是对象”模型的不幸的副作用?

最后,那 loop 构造比 [+] 还原操作员?我认为该循环会导致比减少更多的OPS。

编辑:

我会接受两者 mortiz'沙 hobbs如果可以的话,答案。作为方法调用,一切都是被处理的,更直接地回答了为什么 [+] 很慢,这样就得到了。

有帮助吗?

解决方案

您必须了解缺乏优化的另一件事是 复合. 。写了很大一部分rakudo 在Perl 6中. 。因此,例如 [+] 操作员是通过方法实现的 Any.reduce (打电话给 $expression 调成 &infix:<+>),它具有内在循环

for @.list {
    @args.push($_);
    if (@args == $arity) {
        my $res = $expression.(@args[0], @args[1]);
        @args = ($res);
    }
}

换句话说,纯净的减少实施本身是由Rakudo运行的。因此,您不仅可以 未得到优化,您的代码 看到您的代码运行也没有得到优化。甚至是 + 操作员实际上是方法调用,因为尽管 + 操作员 Num 是由鹦鹉实施的,Rakudo目前尚无意识到您有两个 Nums并优化方法调用,因此在Rakudo找到之前有一个完整的动态调度 multi sub infix:<+>(Num $a, Num $b) 并意识到它真正要做的只是“添加” opcode。这是比Perl 5慢100-1000倍的合理借口:)

更新2010年8月23日

乔纳森·沃辛顿的更多信息 在Perl 6对象模型(或至少Rakudo对其的概念)中需要发生的各种更改,以使事情变得快速,同时保留Perl 6的“一切都是方法称为”的性质。

更新1/10/2019

由于我可以看到这仍然引起人们的注意...多年来,Rakudo/Moarvm已经获得了JIT,内部,动态专业化和 许多人的工作优化系统的每个部分。结果是,大多数方法调用都可以“编译”,并且运行时成本接近零。 Perl 6在许多基准测试的速度上比2010年得分快数百或数千倍,在某些情况下,它比Perl 5快。

对于问题开始的总和100,000的情况,Rakudo 2018.06仍然比Perl 5.26.2慢一点:

$ time perl -e 'use List::Util 'sum'; print sum(1 .. 100000), "\n";' >/dev/null

real    0m0.023s
user    0m0.015s
sys     0m0.008s

$ time perl6 -e 'say [+] 1 .. 100000;' >/dev/null

real    0m0.089s
user    0m0.107s
sys     0m0.022s

但是,如果我们通过运行代码10,000次来摊销启动成本,我们会看到一个不同的故事:

$ time perl -e 'use List::Util 'sum'; for (1 .. 10000) { print sum(1 .. 100000), "\n"; }' > /dev/null

real    0m16.320s
user    0m16.317s
sys     0m0.004s

$ time perl6 -e 'for 1 .. 10000 { say [+] 1 .. 100000; }' >/dev/null

real    0m0.214s
user    0m0.245s
sys     0m0.021s

Perl6在启动和汇编时使用的是Perl5的数百毫秒,但随后它弄清楚了如何更快地完成实际求和的速度约70倍。

其他提示

Rakudo如此缓慢的原因确实有多种原因。

首先,也许最重要的原因是Rakudo尚未进行任何优化。当前的目标是更多探索新功能,并变得更加强大。您知道,他们说:“首先要运行,然后做对,然后使其快速”。

第二个原因是鹦鹉尚未提供任何JIT汇编,而垃圾收集器也不是最快的。有计划编译器的计划,人们正在研究它(前一个被剥夺了,因为它仅是i386,并且是维护噩梦)。还想到将Rakudo移植到其他VM上,但这肯定会等到7月底。

最后,没有人能真正判断出一个完整,优化的Perl 6实现的速度,直到我们有一个实现,但我确实希望它比现在好多了。

顺便说一句您引用的案件 [+] 1..$big_number 可以在o(1)中运行,因为 1..$big_number 返回一个范围,这是内省的。因此,您可以使用总和公式 [+] Range 案子。同样,这是可以做的,但尚未完成。

当然不是因为 一切都是对象, ,因为在其他许多语言中也是如此(例如Ruby)。没有理由为什么Perl 6必须比Perl 5或Ruby等其他语言要慢,但事实是Rakudo不像Perl或Cloby那样成熟。还没有太多的速度优化。

考虑到现在您的测试案例是 优化为 o(1) 算法 几乎可以立即返回,而且似乎几乎每周都有几次优化。
我希望到处都有很大的提高。

$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447

即使这不是特殊的范围,它仍然比以前快得多。
现在,它可以在不到五分之一的时间内进行测试计算。

$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975

我把这些提交给 费菲的语言竞赛 2008年12月。 wp.pugs.pl 是Perl 5示例的字面翻译, wp.rakudo.pl 更棘手。我有两个程序,因为两个程序实现了规格的不同子集。同时,构建信息已过时。来源:

#!/usr/bin/env pugs
# Pugs: <http://pugs.blogs.com/> <http://pugscode.org/>
# prerequisite: ghc-6.8.x, not 6.10.x
# svn co http://svn.pugscode.org/pugs/
# perl Makefile.PL
# make
# if build stops because of haskeline, do:
#   $HOME/.cabal/bin/cabal update ; $HOME/.cabal/bin/cabal install haskeline

# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

for =<> {
    for .split {
        %words{$_}++
    }
}

for (sort { %words{$^b} <=> %words{$^a} }, %words.keys) {
    say "$_ %words{$_}"
}

#!/usr/bin/env perl6
# Rakudo: <http://rakudo.org/> <http://www.parrot.org/download>
# svn co http://svn.perl.org/parrot/trunk parrot
# perl Configure.pl
# make perl6

# Solution contributed by Frank W. & Moritz Lenz
# <http://use.perl.org/~fw/journal/38055>
# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

$*IN.lines.split(/\s+/).map: { %words{$_}++ };

for %words.pairs.sort: { $^b.value <=> $^a.value } -> $pair {
    say $pair
}

这些是2008年的结果:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m2.529s
user    0m2.464s
sys     0m0.064s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo

real    0m32.544s
user    0m1.920s
sys     0m0.248s

今天:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m5.105s
user    0m4.898s
sys     0m0.096s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo
Divide by zero
current instr.: '' pc -1 ((unknown file):-1)
Segmentation fault

real    0m3.236s
user    0m0.447s
sys     0m0.080s

后期加法:坠机事故已被处理 当我尝试使用rakudo运行脚本时,为什么我会得到“零”错误?. 。 Rakudo程序效率低下,请参阅 以下评论http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-peed/.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top