最適化の欠如について理解しなければならないもう1つのことは、それが複合されているということです。Rakudoの大部分はPerl6で書かれています。したがって、たとえば、[+]
演算子は、内部ループとしてAny.reduce
持つメソッド($expression
set toで呼び出される)によって実装されます。&infix:<+>
for @.list {
@args.push($_);
if (@args == $arity) {
my $res = $expression.(@args[0], @args[1]);
@args = ($res);
}
}
言い換えれば、reduceのpure-perl実装であり、それ自体がRakudoによって実行されています。したがって、表示されているコードが最適化されていないだけでなく、コードを実行していると表示されていないコードも最適化されていません。演算子のインスタンスでさえ+
実際にはメソッド呼び出しです。+
演算子onNum
はParrotによって実装されていますが、Rakudoにはまだ2つあることを認識してNum
メソッド呼び出しを最適化するものがないため、Rakudoが検出する前に完全な動的ディスパッチがあります。multi sub infix:<+>(Num $a, Num $b)
そして、それが実際に行っているのは「追加」オペコードだけであることに気づきます。Perl 5よりも100〜1000倍遅いのは合理的な言い訳です:)
2010年8月23日更新
Perl6の「すべてがメソッド呼び出し」の性質を維持しながら物事を高速化するためにPerl6オブジェクトモデル(または少なくともRakudoの概念)で発生する必要のある変更の種類に関するJonathanWorthingtonからの詳細情報。
2019年1月10日更新
これがまだ注目されていることがわかるので...長年にわたって、Rakudo / MoarVMは、システムのあらゆる部分を最適化する多くの人々によって、JIT、インライン化、動的な特殊化、および大量の作業を取得してきました。その結果、これらのメソッド呼び出しのほとんどは「コンパイル」でき、実行時のコストはほぼゼロになります。Perl 6は、多くのベンチマークで2010年よりも数百倍または数千倍高速であり、場合によってはPerl5よりも高速です。
質問が始まった合計が100,000になる問題の場合、Rakudo2018.06はまだperl5.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倍速く行う方法を理解します。