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倍是一个合理的借口:)
来自Jonathan Worthington的更多信息是关于Perl 6对象模型(或至少是Rakudo的概念)需要发生的变化,以便在保留Perl 6的"一切都是方法调用"性质的同时快速完成任务.
因为我可以看到,这仍然是受到关注......多年来,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倍.
考虑到现在您的测试用例已优化为几乎立即返回的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)
当然不是因为一切都是对象,因为在许多其他语言中也是如此(如Ruby).Perl 6没有理由比Perl 5或Ruby等其他语言的速度慢,但事实是Rakudo并不像perl或CRuby那样成熟.目前还没有太多的速度优化.
| 归档时间: |
|
| 查看次数: |
2971 次 |
| 最近记录: |