随着PERL 6实现的成熟,我们可以期待什么绩效?
-
01-10-2019 - |
题
每次我下载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目前尚无意识到您有两个 Num
s并优化方法调用,因此在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/.