Perl 6の実装が成熟するにつれて、どのようなパフォーマンスが増加することができますか?
-
01-10-2019 - |
質問
Rakudo Perl 6の新しいコピーをダウンロードするたびに、現在のパフォーマンスのアイデアを得るためだけに次の式を実行しました。
say [+] 1 .. 100000;
速度は増加していますが、毎回、計算には顕著な遅延(数秒)があります。比較として、Perl 5(または他の解釈言語)でこのようなものはほぼ即座に戻ります。
use List::Util 'sum';
print sum(1 .. 100000), "\n";
またはRuby(ほぼ瞬時):
(1 .. 100000).inject(0) {|sum,x| sum+x}
式をperl6として書き直します loop
最終的には範囲の減少の約2倍の速さになりますが、単純な計算では非常に顕著な遅延(1秒以上)です。
my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}
それで、私の質問は、Perl6実装のどの側面がこれらのパフォーマンスの問題を引き起こしているのですか?そして、これは時間とともに改善されるべきですか、それともこのオーバーヘッドは、Perl6が使用している「すべてがオブジェクトです」モデルの不幸な副作用ですか?
そして最後に、はどうですか loop
コンストラクトはより速いです [+]
削減オペレーター?ループは、削減よりも多くの合計OPSをもたらすと思います。
編集:
両方を受け入れます mortiz
'砂 hobbs
できれば答えます。すべてがメソッドとして処理されていることは、より直接的な理由でより直接的に答えます [+]
遅くなっているので、それを手に入れることができます。
解決
最適化の欠如について理解しなければならないもう1つのことは、 複合. 。 Rakudoの大部分が書かれています Perl 6で. 。たとえば、 [+]
オペレーターはメソッドによって実装されます Any.reduce
(と呼ばれます $expression
に設定 &infix:<+>
)、その内側のループとして
for @.list {
@args.push($_);
if (@args == $arity) {
my $res = $expression.(@args[0], @args[1]);
@args = ($res);
}
}
言い換えれば、それ自体がRakudoによって実行されているRediceの純粋な実装です。そのため、できるコードだけではありません 見る 最適化されていない、あなたのコード しないでください コードを実行することも最適化されていないことを確認してください。のインスタンスでさえ +
オペレーターは実際にはメソッド呼び出しです +
オペレーター Num
Parrotによって実装されていますが、Rakudoにはまだ2つあることを認識するものはまだありません Num
sとメソッド呼び出しを最適化するため、Rakudoが見つける前に完全な動的派遣があります multi sub infix:<+>(Num $a, Num $b)
そして、それが本当にしているのは「追加」オペコードだけであることを認識しています。 Perl 5よりも100〜1000倍遅くなるための合理的な言い訳です:)
2010年8月23日更新
ジョナサン・ワーシントンの詳細 Perl 6オブジェクトモデル(または少なくともRakudoの概念)で発生する必要がある種類の変更については、Perl 6の「Everything Is Method Call」自然を保持しながら物事を速くします。
2019年1月10日更新
私はこれがまだ注目を集めていることがわかるので...長年にわたって、Rakudo/Moarvmはジット、インライン、ダイナミックな専門化、そして トン システムのすべての部分を最適化する多くの人々による作業の。その結果、これらのメソッド呼び出しのほとんどは「コンパイル」され、ランタイムコストがほぼゼロになる可能性があります。 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がまだ最適化を行っていないことです。現在の目標は、より多くの新機能を探求し、より堅牢になることです。彼らは「最初にそれを走らせてから、それを正しくしてから速くする」と言います。
2番目の理由は、オウムがまだJITコンピレーションを提供しておらず、ゴミコレクターが最速ではないことです。 JITコンパイラの計画があり、人々はそれに取り組んでいます(以前のものはI386のみであり、メンテナンスの悪夢だったために破壊されました)。 Rakudoを他のVMに移植するという考えもありますが、それは7月末まで確実に待つでしょう。
最終的には、完全に適切にタイミングされたPerl 6の実装がどれほど速くなるかは、私たちが1つになるまで誰も実際にはわかりませんが、今よりもはるかに優れていると予想しています。
ところで、あなたが引用したケース [+] 1..$big_number
o(1)で実行することができます。 1..$big_number
範囲を返しますが、これは紹介不可能です。したがって、の合計式を使用できます [+] Range
場合。繰り返しますが、それはできることですが、まだ行われていません。
確かにそうではありません すべてがオブジェクトです, 、それは他の多くの言語でも当てはまるからです(Rubyなど)。 Perl 6がPerl 5やRubyのような他の言語よりも大きくなる必要がある理由はありませんが、実際には、RakudoはPerlやCurbyほど成熟していないということです。まだ速度の最適化はあまりありません。
今のテストケースは今それを考慮してください に最適化されています O(1) アルゴリズム それはほぼ即座に戻り、1週間にいくつかの最適化があるように思われます。
パフォーマンスの改善があらゆることを期待しています。
$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447
それが範囲に特別なケースではなかったとしても、それはまだそれよりもかなり速いです。
現在、テスト計算は5分の1未満で行います。
$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975
これらを提出しました Fefeの言語競争 2008年12月。 wp.pugs.pl
Perl 5の例の文字通りの翻訳です。 wp.rakudo.pl
はるかにシチアです。 2つが仕様の異なるサブセットを実装するため、2つのプログラムがあります。一方、ビルド情報は時代遅れです。情報源:
#!/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/.