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.

¿Fue útil?

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 Nums 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/ .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top