2010-06-23 23 views
9

He estado corriendo a través de una gran cantidad de código Perl que rompe las cadenas largas de esta manera:rendimiento con Perl Cuerdas

my $string = "Hi, I am a very long and chatty string that just won't"; 
$string .= " quit. I'm going to keep going, and going, and going,"; 
$string .= " kind of like the Energizer bunny. What are you going to"; 
$string .= " do about it?"; 

De mi experiencia con Java, la construcción de una cadena como esta sería una actuación no- no. ¿Es lo mismo con Perl? En mis búsquedas, he leído que usar join en una matriz de cadenas es la forma más rápida de concatenar cadenas, pero ¿qué ocurre cuando solo quieres dividir una cadena para facilitar la lectura? Es mejor escribir:

my $string = "Hi, I am a very long and chatty string that just won't" . 
    " quit. I'm going to keep going, and going, and going," . 
    " kind of like the Energizer bunny. What are you going to" . 
    " do about it?"; 

O puedo usar join, o cómo debe hacerse?

+1

Algunos encuentran la primera forma más legible. Y no veo ningún motivo realista para preocuparse, que es más rápido. – ysth

+0

@ysth - ¿alguna vez fuiste programador de Java? Entonces lo harías :). – justkt

+0

Eso no tiene sentido. Porque Java es tan "lento"? Porque los programadores de Java son optimizadores prematuros obstinados? – ysth

Respuesta

15

Camel book, p 598:

Prefiero unirse ("", ...) A una serie de cadenas concatenadas. Las múltiples concatenaciones pueden hacer que las cadenas sean copiadas varias veces. El operador de unión lo evita.

+1

Esto podría haber sido rito @ el tiempo escrito. No está en perl 5.18. 'perl -Mstrict -MBenchmark -we 'timethis -10, sub {mi $ salida =" "; foreach (1 .. 10000) {$ output. = chr (rand (127)) x1234; }} ''en mi máquina devuelve' 11 segundos de reloj de pared (10.71 usr + 0.00 sys = 10.71 CPU) @ 491.13/s (n = 5260) 'mientras' perl -Mstrict -MBenchmark -we' timethis -10, sub {my @ trozos; foreach (1 ..10000) {push @chunks, chr (rand (127)) x1234; } my $ output = join ("", @ chunks); } '' devuelve 11 segundos de reloj de pared (10.56 usr + 0.00 sys = 10.56 CPU) a 134.09/s (n = 1416). Este es un factor de 3 que. = Late push + join. –

1

Usa el que más te guste; el rendimiento de esos es exactamente el mismo en Perl. Las cadenas Perl no son como cadenas de Java, y se pueden modificar in situ.

+0

El rendimiento de los dos ejemplos es el mismo, o el rendimiento de 'join' es el mismo que en cualquier ejemplo? Tengo un poco de dificultad para creer que 'join' es el mismo (ya que' join' es generalmente una función nativa), pero si algún lenguaje hubiera optimizado el operador de concatenación de cadenas, estoy seguro de que Sería perl ... –

+0

Concat no es tan eficiente como unirse. Vea mi respuesta por la razón por la cual. –

+2

El rendimiento de ambos ejemplos es el mismo. El rendimiento de 'join' es otra cosa, que puede ser más y puede ser menor. En cualquier caso, perl no es un lenguaje de alto rendimiento y es poco probable que el costo de la concatenación de cadenas o la invocación 'join 'sea lo más importante. –

3

La principal diferencia de rendimiento entre los dos ejemplos es que en el primero, la concatenación ocurre cada vez que se invoca el código, mientras que en el segundo, el compilador plega las cadenas constantes.

De modo que si alguno de estos ejemplos estará en un bucle o función llamada muchas veces, el segundo ejemplo será más rápido.

Esto supone que las cadenas se conocen en tiempo de compilación. Si está creando las cadenas en tiempo de ejecución, como menciona fatcat1111, el operador join será más rápido que la concatenación repetida.

-1

No necesita hacer nada de eso, puede simplemente asignar toda la cadena a una variable a la vez.

my $string = "Hi, I am a very long and chatty string that just won't 
quit. I'm going to keep going, and going, and going, 
kind of like the Energizer bunny. What are you going to 
do about it?"; 
+6

Eso incluirá nuevas líneas en la cadena, que probablemente no es lo que el usuario quiere. – Ether

+0

@Ether - correcto. Apoyos para no llamarme "él", por cierto. Sucede todo el tiempo, por alguna razón, cuando no soy hombre. – justkt

+0

@justkt: Yo tampoco. * high5 * :) – Ether

11

Una cosa más que añadir a este tema que no se ha mencionado todavía - si se puede, evitar unirse a/concatenación de estas cadenas. Muchos métodos se llevarán una lista de cadenas como argumentos, no sólo una cadena, por lo que sólo pueden pasar de forma individual, por ejemplo .:

print "this is", 
    " perfectly legal", 
    " because print will happily", 
    " take a list and send all the", 
    " strings to the output stream\n"; 

die "this is also", 
    " perfectly acceptable"; 

use Log::Log4perl :easy; use Data::Dumper; 
INFO("and this is just fine", 
    " as well"); 

INFO(sub { 
    local $Data::Dumper::Maxdepth = 1; 
    "also note that many libraries will", 
    " accept subrefs, in which you", 
    " can perform operations which", 
    " return a list of strings...", 
    Dumper($obj); 
}); 
+0

Esto es muy bueno saberlo. – justkt

10

Hice el punto de referencia! :)

#!/usr/bin/perl 

use warnings; 
use strict; 

use Benchmark qw(cmpthese timethese); 

my $bench = timethese($ARGV[1], { 

    multi_concat => sub { 
    my $string = "Hi, I am a very long and chatty string that just won't"; 
    $string .= " quit. I'm going to keep going, and going, and going,"; 
    $string .= " kind of like the Energizer bunny. What are you going to"; 
    $string .= " do about it?"; 
    }, 

    one_concat => sub { 
    my $string = "Hi, I am a very long and chatty string that just won't" . 
    " quit. I'm going to keep going, and going, and going," . 
    " kind of like the Energizer bunny. What are you going to" . 
    " do about it?"; 
    }, 

    join => sub { 
    my $string = join("", "Hi, I am a very long and chatty string that just won't", 
    " quit. I'm going to keep going, and going, and going,", 
    " kind of like the Energizer bunny. What are you going to", 
    " do about it?" 
    ); 
    }, 

}); 

cmpthese $bench; 

1; 

Los resultados (en mi iMac con Perl 5.8.9):

imac:Benchmarks seb$ ./strings.pl 1000 
Benchmark: running join, multi_concat, one_concat for at least 3 CPU seconds... 
     join: 2 wallclock secs (3.13 usr + 0.01 sys = 3.14 CPU) @ 3235869.43/s (n=10160630) 
multi_concat: 3 wallclock secs (3.20 usr + -0.01 sys = 3.19 CPU) @ 3094491.85/s (n=9871429) 
one_concat: 2 wallclock secs (3.43 usr + 0.01 sys = 3.44 CPU) @ 12602343.60/s (n=43352062) 
        Rate multi_concat   join one_concat 
multi_concat 3094492/s   --   -4%   -75% 
join   3235869/s   5%   --   -74% 
one_concat 12602344/s   307%   289%   -- 
+7

'one_concat' es optimizado por el compilador en una asignación constante con 0 concatenaciones en tiempo de ejecución. –

+0

@Eric. Gracias, eso más o menos responde mi pregunta original. – justkt

2

En mis puntos de referencia, join es sólo marginalmente más rápido que la concatenación con la reasignación y sólo en las listas cortas de cadenas. La concatenación sin reasignación es significativamente más rápida que cualquiera de las dos. En listas más largas, join funciona notablemente peor que la concatenación con reasignación, probablemente porque el paso de argumentos comienza a dominar el tiempo de ejecución.

4 strings: 
      Rate .= join . 
.= 2538071/s -- -4% -18% 
join 2645503/s 4% -- -15% 
. 3105590/s 22% 17% -- 
1_000 strings: 
     Rate join .= 
join 152439/s -- -40% 
.= 253807/s 66% -- 

Así que en términos de su pregunta, ..= latidos de tiempo de ejecución, aunque no lo suficiente que es por lo general vale la pena preocuparse. La legibilidad casi siempre es más importante que el rendimiento, y .= es a menudo una forma más legible.

Esto es en el caso general; como sebthebert's answer demuestra, . es mucho más rápido que .= en el caso de concatenación de constantes que me gustaría tratar como regla.

(Los puntos de referencia, por cierto, son, básicamente, en forma obvia y voy prefieren no repetir el código aquí. Lo único sorprendente es la creación de las cadenas iniciales de <DATA> fin de frustrar plegado constante.)

D'A