随着Perl 6实现的成熟,我们可以期待什么性能提升?

Eri*_*rom 27 perl performance rakudo perl6 raku

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

say [+] 1 .. 100000;
Run Code Online (Sandbox Code Playgroud)

并且速度一直在增加,但每次计算都有明显的延迟(几秒).作为比较,Perl 5(或其他解释语言)中的类似内容几乎立即返回:

use List::Util 'sum';

print sum(1 .. 100000), "\n";
Run Code Online (Sandbox Code Playgroud)

或者在Ruby中(也几乎是即时的):

(1 .. 100000).inject(0) {|sum,x| sum+x}
Run Code Online (Sandbox Code Playgroud)

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

my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,Perl6实现的哪些方面导致了这些性能问题?并且这应该随着时间的推移而改善,还是这个开销是Perl6使用的"一切都是对象"模型的不幸副作用?

最后,loop构造比[+]减速算子更快吗?我认为循环将导致更多的总操作而不是减少.

编辑:

我会接受这两个mortiz年代和hobbs'如果我能的回答.一切都是作为一个方法调用处理更直接地回答为什么[+]慢,所以一个人得到它.

mor*_*itz 22

Rakudo如此缓慢有各种各样的原因.

第一个也许是最重要的原因是Rakudo还没有进行任何优化.目前的目标是更多探索新功能,并变得更加强大.你知道,他们说"首先使它运行,然后使其正确,然后使其快速".

第二个原因是parrot还没有提供任何JIT编译,垃圾收集器也不是最快的.有一个JIT编译器的计划,人们正在研究它(之前的一个被删除,因为它只是i386和维护噩梦).还有将Rakudo移植到其他虚拟机的想法,但这肯定会等到7月底之后.

最后,没有人能够真正地告诉我们有一个完整的,经过优化的完整Perl 6实现的速度,但我确实认为它比现在要好得多.

BTW你引用的案例[+] 1..$big_number可以在O(1)中运行,因为1..$big_number返回一个范围,这是内省的.因此,您可以使用[+] Range案例的总和公式.再一次,这是可以完成的事情,但尚未完成.


hob*_*bbs 17

关于缺乏优化,你必须要了解的另一件事是它复杂化了.Rakudo的很大一部分是用Perl 6编写的.因此,例如,[+]运算符由方法实现Any.reduce(使用$expressionset to 调用&infix:<+>),其具有内部循环

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

换句话说,一个pure-perl实现reduce,它本身由Rakudo运行.因此,您看到的代码不仅没有得到优化,而且您没有看到使代码运行的代码也没有得到优化.甚至+运算符的实例实际上都是方法调用,因为虽然+运算符Num是由Parrot实现的,但是Rakudo中还没有任何东西可以识别你有两个Num并且优化掉方法调用,所以在Rakudo发现之前有一个完整的动态调度multi sub infix:<+>(Num $a, Num $b)并意识到它所做的一切都是"添加"操作码.这比Perl 5慢100-1000倍是一个合理的借口:)

2010年8月23日更新

来自Jonathan Worthington的更多信息是关于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
Run Code Online (Sandbox Code Playgroud)

但是,如果我们通过运行代码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
Run Code Online (Sandbox Code Playgroud)

在启动和编译时,perl6比perl5使用几百毫秒,但它会弄清楚如何将实际求和速度提高约70倍.


Bra*_*ert 6

考虑到现在您的测试用例已优化为几乎立即返回O(1)算法,并且似乎每周有几次优化;
我期望全面的性能改进。

$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447
Run Code Online (Sandbox Code Playgroud)

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

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


Leo*_*ans 5

当然不是因为一切都是对象,因为在许多其他语言中也是如此(如Ruby).Perl 6没有理由比Perl 5或Ruby等其他语言的速度慢,但事实是Rakudo并不像perl或CRuby那样成熟.目前还没有太多的速度优化.