Lo que aumenta el rendimiento podemos esperar que las implementaciones de Perl 6 maduran?
-
01-10-2019 - |
Pregunta
Cada vez que he descargado una nueva copia de Rakudo Perl 6, he corrido la expresión siguiente sólo para tener una idea de su rendimiento actual:
say [+] 1 .. 100000;
Y las velocidades han ido en aumento, pero cada vez, hay un retraso notable (varios segundos) para el cálculo. A modo de comparación, algo como esto en Perl 5 (u otros lenguajes interpretados) devuelve casi al instante:
use List::Util 'sum';
print sum(1 .. 100000), "\n";
o en Ruby (también casi instantánea):
(1 .. 100000).inject(0) {|sum,x| sum+x}
Reescribiendo la expresión como una extremos loop
Perl6 siendo aproximadamente dos veces tan rápido como la reducción de la gama, pero es todavía un retraso muy notable (más de un segundo) para el cálculo simple:
my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}
Así que mi pregunta es, ¿qué aspectos de la aplicación Perl6 están causando estos problemas de rendimiento? Y si esto mejora con el tiempo, o se trata de sobrecarga de un efecto secundario desafortunado del "todo es un objeto" modelo que Perl6 está utilizando?
Y por último, ¿qué pasa con el constructo loop
es más rápido que el operador reducción [+]
? Me gustaría pensar que el bucle se traduciría en más operaciones totales que la reducción.
EDIT:
Me acepto ambos de mortiz
y respuestas de hobbs
si pudiera. Que todo es un ser manejado como una llamada al método responde más directamente por qué [+]
está siendo lenta, por lo que se obtiene la misma.
Solución
Otra cosa que hay que entender acerca de la falta de optimización es que es agravado . Una gran parte de Rakudo está escrito en Perl 6 . Así, por ejemplo el operador [+]
es implementado por el Any.reduce
método (llamado con el conjunto $expression
a &infix:<+>
), que tiene como su bucle interior
for @.list {
@args.push($_);
if (@args == $arity) {
my $res = $expression.(@args[0], @args[1]);
@args = ($res);
}
}
En otras palabras, una implementación de Perl puro de reducir, que a su vez está siendo dirigido por Rakudo. Así que no sólo es el código que puede ver no conseguir optimizados, el código que ha no de ver que haciendo que su código también no está recibiendo
optimizado. incluso casos de operador +
son en realidad las llamadas de método, ya que si bien el operador +
en Num
se implementa por Parrot, no hay nada todavía en Rakudo reconocer que tienes dos Num
s y optimizar la distancia de la llamada al método, por lo que hay un despacho dinámico completo antes Rakudo encuentra multi sub infix:<+>(Num $a, Num $b)
y se da cuenta de que todo lo que está haciendo en realidad es un código de operación 'añadir'. Es una excusa razonable por ser más lento que 100-1000x Perl 5:)
Actualización 8/23/2010
Más información de Jonathan Worthington en los tipos de cambios que deben ocurrir con el modelo de objetos de Perl 6 (o al menos la concepción de Rakudo de ella) para hacer las cosas rápido, manteniendo Perl 6 "todo es llamadas de método" de la naturaleza.
Actualización del 01/10/2019
Desde que puedo ver que esto todavía es llamar la atención ... lo largo de los años, Rakudo / MoarVM haber conseguido JIT, inline, la especialización dinámica, y toneladas de trabajo de muchas personas optimización de todas las partes de el sistema. El resultado es que la mayoría de esas llamadas método puede ser "compilado a cabo" y tienen casi cero costo en tiempo de ejecución. Perl 6 puntuaciones de cientos o miles de veces más rápido en muchos puntos de referencia que lo hizo en 2010, y en algunos casos es más rápido que Perl 5.
En el caso del problema de la suma-a-100000 que la cuestión se inició con, Rakudo 2018.06 es todavía un poco más lento que el 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
Pero si fuera amortizar el costo de inicio ejecutando el código de 10.000 veces, vemos una historia diferente:
$ 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 utiliza unos pocos cientos de milisegundos más que perl5 en el arranque y la compilación, pero luego se da cuenta de cómo hacer la suma real de alrededor de 70 veces más rápido.
Otros consejos
Existen muy diversas razones por las Rakudo es tan lento.
La primera y tal vez más importante razón es que Rakudo no hace ninguna optimización todavía. Los objetivos actuales son más explorar nuevas características, y para ser más robusto. Ya sabes, dicen "primero hacer que se ejecute, a continuación, hacer las cosas bien, a continuación, que sea rápido".
La segunda razón es que el loro no ofrece ninguna compilación JIT todavía, y el recolector de basura no es el más rápido. Hay planes para un compilador JIT, y las personas están trabajando en ello (la anterior fue arrancado porque era la arquitectura i386 y una pesadilla de mantenimiento). También hay pensamientos de portar Rakudo a otras máquinas virtuales, pero que seguramente prefiere esperar hasta después de finales de julio.
Al final, nadie puede realmente decir qué tan rápido un completo bien optimizado aplicación, Perl 6 será hasta que tengamos uno, pero espero que sea mucho mejor que ahora.
Por cierto, el caso ha citado [+] 1..$big_number
podría ser obligado a correr en O (1), porque los rendimientos 1..$big_number
un rango, que es introspectable. Por lo tanto se puede utilizar una fórmula de la suma para el caso [+] Range
. Una vez más se trata de algo que se podía hacer, pero que no se ha hecho todavía.
Desde luego, no se debe a todo es un objeto , porque eso es cierto en un número de otros idiomas también (como Ruby). No hay ninguna razón por qué Perl 6 tendría que ser magnitudes más lento que otros lenguajes como Perl o Ruby 5, pero el hecho es que Rakudo no está tan madura como Perl o CRuby. No ha habido mucha optimización de la velocidad todavía.
Teniendo en cuenta que ahora el caso de test es optimizado para un O (1) algoritmo que vuelve casi al instante, y que parece casi como hay varias optimizaciones a la semana;
Espero una gran mejora de rendimiento por todas partes.
$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447
Incluso si no que fue con carcasa especial para rangos todavía es un poco más rápido de lo que era.
Ahora se hace el cálculo de su prueba en menos de una quinta parte de un segundo.
$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975
Me presentó a estos de Fefe lenguaje de la competencia en diciembre de 2008. wp.pugs.pl
es una traducción literal del 5 ejemplo Perl, wp.rakudo.pl
es mucho más sixier. Tengo dos programas porque los dos implemento un subconjunto diferente de la especificación. Construir la información es obsoleta por su parte. Las fuentes:
#!/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
}
Estos fueron los resultados 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
Hoy:
$ 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
adiciones tardías: El accidente se ha tratado en ¿Por qué recibo 'divide por las negativas errores cuando trato de ejecutar mi script con Rakudo ? . El programa Rakudo es ineficiente, consulte debajo y http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/ .