Quelle performance augmente peut-on attendre que les implémentations Perl 6 mûrissent?
-
01-10-2019 - |
Question
Chaque fois que j'ai téléchargé une nouvelle copie de Rakudo Perl 6, j'ai couru l'expression suivante juste pour avoir une idée de sa performance actuelle:
say [+] 1 .. 100000;
Et les vitesses ont augmenté, mais à chaque fois, il y a un retard notable (plusieurs secondes) pour le calcul. A titre de comparaison, quelque chose comme ça en Perl 5 (ou d'autres langues interprétées) retourne presque instantanément:
use List::Util 'sum';
print sum(1 .. 100000), "\n";
ou Ruby (aussi presque instantanée):
(1 .. 100000).inject(0) {|sum,x| sum+x}
Réécrire l'expression comme extrémités de loop
Perl6 par être environ deux fois plus vite que la réduction de la gamme, mais il est encore un retard très sensible (plus d'une seconde) pour le calcul simple:
my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}
Alors, ma question est, quels sont les aspects de la mise en œuvre Perl6 sont à l'origine de ces problèmes de performance? Et si cela s'améliorer avec le temps, ou est-ce au-dessus d'un effet secondaire malheureux du modèle « tout est un objet » que Perl6 utilise?
Et enfin, qu'en la construction loop
est plus rapide que l'opérateur de réduction de [+]
? Je pense que la boucle entraînerait ops plus au total que la réduction.
EDIT:
J'accepte les deux de la mortiz
et les réponses de hobbs
si je pouvais. Que tout est un être traité comme un appel de méthode plus répond directement pourquoi [+]
est d'être lent, de sorte que l'on obtient.
La solution
Une autre chose que vous devez comprendre au sujet du manque d'optimisation est qu'il est COMPOSÉ . est écrit une grande partie de Rakudo en Perl 6 . Ainsi, par exemple l'opérateur de [+]
est mis en oeuvre par le procédé Any.reduce
(appelée avec jeu de $expression
à &infix:<+>
), qui a pour boucle interne
for @.list {
@args.push($_);
if (@args == $arity) {
my $res = $expression.(@args[0], @args[1]);
@args = ($res);
}
}
autrement dit, une mise en œuvre pure perl de réduire, ce qui est lui-même dirigé par Rakudo. Ainsi, non seulement est le code que vous pouvez voir Ne pas obtenir optimisé, le code que vous ne pas voyez que de faire tourner votre code est également ne reçoit pas
optimisé. instances même de l'opérateur +
sont en fait des appels de méthode, car, bien que l'opérateur +
sur Num
est mis en œuvre par Parrot, il n'y a rien encore Rakudo de reconnaître que vous avez deux Num
s et optimize loin l'appel de méthode, donc il y a une dépêche de dynamique complète avant Rakudo trouve multi sub infix:<+>(Num $a, Num $b)
et se rend compte que tout cela fait vraiment est un opcode « ajouter ». Il est une excuse raisonnable pour être 100-1000x plus lent que Perl 5:)
Mise à jour 8/23/2010
Plus d'informations de Jonathan Worthington sur les types de changements qui doivent se produire avec le modèle objet Perl 6 (ou au moins la conception de Rakudo de celui-ci) pour faire les choses rapidement tout en conservant la nature « tout est appels de méthode » de Perl 6.
Mise à jour 10/01/2019
Depuis que je peux voir que cela encore ... pour attirer l'attention au fil des ans, Rakudo / MoarVM ont obtenu JIT, inline, spécialisation dynamique et tonnes de travail par beaucoup de gens optimiser chaque partie le système. Le résultat est que la plupart de ces appels de méthode peut être « compilé sur » et ont presque zéro coût d'exécution. cliquer ici Perl 6 des centaines ou des milliers de fois plus rapide sur de nombreux points de référence qu'il a fait en 2010, et dans certains cas, il est plus rapide que Perl 5.
Dans le cas du problème somme à 100 000 que la question a commencé avec, Rakudo 2018,06 est encore un peu plus lent que 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
Mais si nous amortissons sur les coûts de démarrage en exécutant le code 10000 fois, nous voyons une autre histoire:
$ 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 utilise quelques centaines de millisecondes plus que perl5 au démarrage et la compilation, mais il figure comment faire la somme réelle environ 70 fois plus rapide.
Autres conseils
Il y a vraiment diverses raisons pour lesquelles Rakudo est si lent.
La première et peut-être plus importante raison est que Rakudo ne fait aucune optimisations encore. Les objectifs actuels sont plus explorent de nouvelles fonctionnalités, et de devenir plus robuste. Vous savez, ils disent « d'abord le faire fonctionner, puis le faire à droite, puis le faire rapidement ».
La deuxième raison est que le perroquet ne propose pas encore de compilation JIT, et le garbage collector est pas le plus rapide. Il y a des plans pour un compilateur JIT, et les gens y travaillent (le précédent a été arraché parce qu'il était i386 et un cauchemar de maintenance). Il y a aussi des pensées de portage Rakudo à d'autres machines virtuelles, mais qui vont sûrement attendre jusqu'à après la fin de Juillet.
En fin de compte, personne ne peut vraiment dire à quelle vitesse une complète, la mise en œuvre Perl 6 bien optimisé sera jusqu'à ce que nous avons, mais je ne pensais que ce serait beaucoup mieux que maintenant.
BTW le cas que vous avez cité [+] 1..$big_number
pourrait être fait pour fonctionner en O (1), parce que les rendements de 1..$big_number
une plage, qui est introspecter. Vous pouvez donc utiliser une formule de somme pour le cas [+] Range
. Encore une fois, il y a quelque chose qui pourrait être fait, mais cela n'a pas encore été fait.
Il est certainement pas parce que tout est un objet , parce que c'est vrai dans un certain nombre d'autres langues (comme Ruby). Il n'y a aucune raison pour laquelle Perl 6 devrait être magnitudes plus lent que d'autres langages comme Perl 5 ou Ruby, mais le fait est que Rakudo est pas aussi mature que perl ou CRuby. Il n'a pas encore été beaucoup optimisation de la vitesse.
Considérant maintenant votre cas de test est optimisé pour un O (1) algorithme que les rendements presque instantanément, et qu'il semble presque comme il y a plusieurs optimisations par semaine;
Je pense tout à fait une amélioration de la performance tout autour.
$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447
Même si cela n'a pas été spécial tubé pour les plages, il est encore un peu plus rapide que c'était.
Il fait maintenant votre calcul de test en moins d'un cinquième de seconde.
$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975
Je soumis ces concours des langues Fefe en Décembre 2008. wp.pugs.pl
est une traduction littérale de l'exemple Perl 5, wp.rakudo.pl
est beaucoup plus sixier. J'ai deux programmes parce que les deux sous-ensemble mettre en œuvre un autre de la spécification. informations de construction est obsolète quant à lui. Les sources:
#!/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
}
Ce sont les résultats en 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
Aujourd'hui:
$ 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
additions tardives: Le crash a été traité Pourquoi est-ce que je reçois « diviser par zero` erreurs lorsque je tente de lancer mon script avec Rakudo . Le programme Rakudo est inefficace, voir et http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/ .