Ciò che aumenta le prestazioni ci si può aspettare, come i Perl 6 implementazioni maturare?
-
01-10-2019 - |
Domanda
Ogni volta che ho scaricato una nuova copia di Rakudo Perl 6, ho eseguito la seguente espressione solo per avere un'idea delle sue prestazioni attuali:
say [+] 1 .. 100000;
E i costi sono aumentati, ma ogni volta, c'è un ritardo notevole (alcuni secondi) per il calcolo. A titolo di confronto, qualcosa di simile a Perl 5 (o altri linguaggi interpretati) restituisce quasi immediatamente:
use List::Util 'sum';
print sum(1 .. 100000), "\n";
o in rubino (anche quasi istantanea):
(1 .. 100000).inject(0) {|sum,x| sum+x}
Riscrittura l'espressione come un Perl6 estremità loop
per essere circa due volte più veloce riducendo la portata, ma è ancora un ritardo molto evidente (più di un secondo) per il calcolo semplice:
my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}
Quindi la mia domanda è, cosa aspetti dell'attuazione Perl6 stanno causando questi problemi di prestazioni? E questo dovrebbe migliorare con il tempo, o è questo overhead un effetto collaterale del "tutto è un oggetto" modello che Perl6 sta usando?
E, infine, per quanto riguarda il costrutto loop
è più veloce l'operatore di riduzione [+]
? Vorrei pensare che il ciclo si tradurrebbe in ops più totale rispetto della riduzione.
EDIT:
Mi piacerebbe accettare sia di mortiz
e se potessi le risposte di hobbs
. Che tutto è un essere gestita come una chiamata di metodo più diretto Risposte Perché [+]
è essere lento, in modo che si ottiene.
Soluzione
Un'altra cosa che dovete capire circa la mancanza di ottimizzazione è che si tratta di aggravata ??em>. Una gran parte di Rakudo è scritto in Perl 6 . Così per esempio l'operatore [+]
è implementato il metodo Any.reduce
(chiamato con $expression
set di &infix:<+>
), che ha come ciclo interno
for @.list {
@args.push($_);
if (@args == $arity) {
my $res = $expression.(@args[0], @args[1]);
@args = ($res);
}
}
in altre parole, un'implementazione pura Perl di ridurre, che a sua volta è gestito da Rakudo. Quindi non solo è il codice è possibile vedere non ottenere ottimizzati, il codice che si non vedere che sta facendo la corsa codice non è anche sempre
ottimizzato. istanze Anche dell'operatore +
sono in realtà chiamate a metodi, in quanto anche se l'operatore +
su Num
è implementato da Parrot, non c'è ancora nulla in Rakudo di riconoscere che hai due Num
s e ottimizzare via la chiamata di metodo, quindi non c'è un dispaccio piena dinamica prima Rakudo trova multi sub infix:<+>(Num $a, Num $b)
e si rende conto che tutto quello che sta realmente facendo è un codice operativo 'add'. E 'una scusa ragionevole per essere 100-1000x più lento di Perl 5:)
Aggiornamento 2010/08/23
Maggiori informazioni da Jonathan Worthington sul tipo di cambiamenti che devono accadere con il modello a oggetti Perl 6 (o almeno la concezione di Rakudo di esso) per rendere le cose velocemente, pur mantenendo Perl 6 del "tutto è chiamate di metodo" la natura.
Aggiornamento 2019/01/10
Dato che posso vedere che questo è ancora ottenendo l'attenzione ... nel corso degli anni, Rakudo / MoarVM hanno ottenuto JIT, inlining, la specializzazione dinamica, e tonnellate di lavoro da parte tante persone ottimizzando ogni parte del il sistema. Il risultato è che la maggior parte di quelle chiamate metodo può essere "compilato out" e hanno quasi zero costi di esecuzione. Perl 6 colonne sonore centinaia o migliaia di volte più veloce su molti punti di riferimento di quello che ha fatto nel 2010, e in alcuni casi è più veloce di Perl 5.
Nel caso del problema somma da 100.000 che la questione è iniziato con, Rakudo 2018,06 è ancora un po 'più lento rispetto 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
Ma se ammortizzare il costo di avvio eseguendo il codice di 10.000 volte, vediamo una storia diversa:
$ 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 utilizza a poche centinaia di millisecondi più di perl5 all'avvio e la compilazione, ma poi capisce come fare la somma effettiva di circa 70 volte più veloce.
Altri suggerimenti
Ci sono davvero diversi motivi per cui Rakudo è così lento.
Il primo e forse più importante motivo è che Rakudo non fa ancora ottimizzazioni. Gli obiettivi attuali sono più esplorano nuove caratteristiche, e per diventare più robusto. Sai, si dice "prima farlo funzionare, allora ne fanno a destra, poi fare in fretta".
La seconda ragione è che il pappagallo non offre alcuna compilazione JIT ancora, e il garbage collector non è il più veloce. Ci sono piani per un compilatore JIT, e le persone stanno lavorando su di esso (il precedente è stato strappato fuori perché era i386 solo e un incubo di manutenzione). Ci sono anche i pensieri di porting Rakudo per altre macchine virtuali, ma che sarà sicuramente aspettare fino dopo la fine del mese di luglio.
Alla fine, nessuno può veramente dire quanto velocemente una, ben ottimizzato completa implementazione Perl 6 sarà fino a quando abbiamo una, ma mi aspetto che sia molto meglio di adesso.
A proposito del caso citato [+] 1..$big_number
potrebbe essere fatto per l'esecuzione in O (1), in quanto i rendimenti 1..$big_number
un intervallo, che è introspectable. Così si può utilizzare una formula somma per il caso [+] Range
. Anche in questo caso si tratta di qualcosa che potrebbe essere fatto, ma che non è stato ancora fatto.
Non è certo perché Tutto è un oggetto , perché questo è vero in un certo numero di altre lingue troppo (come Ruby). Non c'è alcun motivo per cui Perl 6 dovrebbe essere magnitudini più lento di altri linguaggi come Perl 5 o Ruby, ma il fatto è che Rakudo non è così maturo come Perl o CRuby. Non c'è stata ancora l'ottimizzazione della velocità molto.
Considerando che ora la tua test è ottimizzato per un O (1) algoritmo che i rendimenti quasi istantaneamente, e che sembra quasi come ci sono diverse ottimizzazioni alla settimana;
Mi aspetto piuttosto un miglioramento delle prestazioni in tutto.
$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447
Anche se questo non è stato speciale carter per le gamme è ancora un po 'più veloce di quanto non fosse.
Ora fa il calcolo di prova in meno di un quinto di secondo.
$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975
ho presentato questi per di Fefe lingua concorrenza nel dicembre 2008. wp.pugs.pl
è una traduzione letterale del Perl 5 esempio, wp.rakudo.pl
è molto più sixier. Ho due programmi perché i due attuare un diverso sottoinsieme delle specifiche. informazioni di build è obsoleto nel frattempo. Le fonti:
#!/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
}
Questi sono stati i risultati del 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
Oggi:
$ 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
integrazioni tardivi: Il crollo è stato affrontato a Perché ricevo 'dividere per zero` errori quando si tenta di eseguire il mio script con Rakudo ? . Il programma Rakudo è inefficiente, vedi sotto e http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/ .