Tengo una secuencia de comandos Perl que procesa una gran cantidad de datos. Hay un montón de variables de cadena que comienzan pequeñas pero crecen mucho debido al uso repetido del operador de punto (concatenación). ¿El crecimiento de la cuerda de esta manera dará como resultado reasignaciones repetidas? En caso afirmativo, ¿hay alguna manera de preasignar una cadena?¿Cómo puedo preasignar una cadena en Perl?
Respuesta
Sí, las cuerdas preextendidas que usted sabe que crecerán son una buena idea.
Puede usar el operador 'x' para hacer esto. Por ejemplo, para asignar previamente: 1000 plazas
$ s = "" x 1000:
Y luego use substr en el lhs de las asignaciones. Uuuuugly. – chaos
Mientras que esto creará una cadena que contiene 1000 plazas, cuando luego decir "$ s = 'foo'", voy a recibir una cadena de 1.000 caracteres con sólo los tres primeros utilizado o va a darme una nueva cadena de 3 caracteres y ¿tirar el tuyo? (Sospecho que este último, pero en realidad no sé cómo lo manejarán Perl.) –
Si reasigna él, se tire el resultado de edad (suponiendo distancia referencias a ella). Tendría que hacer un reemplazo de cadena, como dijo Dave, para modificar solo partes de ella. ++ array-then-join – Anonymous
cadenas de Perl son mutables, por lo que anexar a una cadena hace NO incurrir en una penalización cadena de duplicación.
Puede probar todo lo que quiera para encontrar una manera "más rápida", pero esto huele realmente mal a la optimización prematura.
Por ejemplo, aumenté una clase que abstraía el trabajo duro. Funciona perfectamente, pero es, a pesar de todos sus trucos tontos, realmente lento.
Aquí está el resultado:
Rate magic normal
magic 1.72/s -- -93%
normal 23.9/s 1289% --
Sí, eso es correcto, Perl es un 1200% más rápido de lo que pensaba era un respetable aplicación.
Perfile su código y descubra cuáles son los verdaderos problemas, no intente optimizar cosas que ni siquiera son un problema conocido.
#!/usr/bin/perl
use strict;
use warnings;
{
package MagicString;
use Moose;
has _buffer => (
isa => 'Str',
is => 'rw',
);
has _buffer_size => (
isa => 'Int',
is => 'rw',
default => 0,
);
has step_size => (
isa => 'Int',
is => 'rw',
default => 32768,
);
has _tail_pos => (
isa => 'Int',
is => 'rw',
default => 0,
);
sub BUILD {
my $self = shift;
$self->_buffer(chr(0) x $self->step_size);
}
sub value {
my $self = shift;
return substr($self->{buffer}, 0, $self->{_tail_pos});
}
sub append {
my $self = shift;
my $value = shift;
my $L = length($value);
if (($self->{_tail_pos} + $L) > $self->{_buffer_size }){
$self->{buffer} .= (chr(0) x $self->{step_size});
$self->{_buffer_size} += $self->{step_size};
}
substr($self->{buffer}, $self->{_tail_pos}, $L, $value);
$self->{_tail_pos} += $L;
}
__PACKAGE__->meta->make_immutable;
}
use Benchmark qw(:all :hireswallclock);
cmpthese(-10 , {
magic => sub{
my $x = MagicString->new();
for (1 .. 200001){
$x->append("hello");
}
my $y = $x->value();
},
normal =>sub{
my $x = '';
for (1 .. 200001){
$x .= 'hello';
}
my $y = $x;
}
});
#use Data::Dumper;
#print Dumper(length($x->value()));
Decir que Perl no duplica la cadena es solo la mitad de la verdad. Perl asigna solo unos pocos caracteres extra a una cadena, por lo que es probable que Perl haga crecer la memoria que contiene la cadena cuando se agrega. Esto puede causar que la memoria sea copiada. Pero esto sucede en el administrador de memoria de su sistema, que es muy rápido. Recuerde, O (n) vencerá a O (logn) en la clase de matemáticas, pero en el mundo real importa el tiempo constante del algoritmo. C es rápido. – Schwern
De hecho, O (1) no es muy bueno si O (1) es de varios días de un paso, mientras que O (n^2) puede tomar sólo unos segundos :) Aunque, tal vez una ventaja si el tamaño de los datos es tan grande que el enfoque O (n^2) excede varias semanas y que el conjunto de datos de tamaño es común. –
Sí, Perl crecer una cadena dará lugar a reasignaciones repetidas. Perl asigna un poco de espacio extra a las cadenas, pero solo unos pocos bytes. Puedes ver esto usando Devel :: Peek. Esta reasignación es muy rápida y, a menudo, no copia realmente la memoria. Confíe en su administrador de memoria, esa es la razón por la que está programando en Perl y no en C. ¡Haga una evaluación comparativa primero!
Puede preasignar matrices con $#array = $num_entries
y un hash con keys %hash = $num_keys
pero length $string = $strlen
no funciona. Aquí hay un clever trick I dug up on Perlmonks.
my $str = "";
vec($str, $length, 8)=0;
$str = "";
O si lo desea conseguir en XS puede llamar SvGROW()
.
La sugerencia de caos de utilizar un conjunto y luego unirlo todo utilizará más del doble de la memoria. Memoria para la matriz. Memoria para cada escalar asignado para cada elemento en la matriz. Memoria para la cadena sostenida en cada elemento escalar. Memoria para la copia cuando se une. Si resulta en un código más simple, hágalo, pero no crea que está guardando memoria.
me gustaría ir la matriz/unirse manera:
push(@array, $crunched_bit)
Y luego $str = join('', @array)
, si nada más, para tener acceso a todos los elementos para la depuración en algún momento posterior.
Esto consumirá una gran cantidad de memoria extra ya que cada elemento de la matriz necesita un nuevo SV. –
No sé específicamente cómo se implementan las cadenas de Perl, pero una muy buena suposición es que es constant amortized time. Esto significa que incluso si usted encuentra una manera de asignar previamente sus posibilidades de cuerdas son que el tiempo combinado que ahorrará para todos los usuarios del guión será menor que el tiempo que pasó pidiendo this question desbordamiento de pila.
- 1. ¿Cómo puedo encapsular una cadena en Perl?
- 2. ¿Cómo puedo convertir una cadena en un número en Perl?
- 3. ¿Cómo puedo adivinar la codificación de una cadena en Perl?
- 4. ¿Cómo puedo citar una cadena larga en Perl?
- 5. ¿Cómo puedo extraer subcadenas de una cadena en Perl?
- 6. ¿Cómo puedo interpolar un elemento hash Perl en una cadena?
- 7. ¿Cómo puedo escapar cosas de código en una cadena Perl?
- 8. ¿Cómo puedo pegar HTML en una cadena usando Perl?
- 9. ¿Cómo puedo verificar si una cadena Perl contiene letras?
- 10. ¿Cómo preasignar una matriz de clase en MATLAB?
- 11. ¿Cómo convierto una cadena binaria en un número en Perl?
- 12. perl cómo convertir una cadena a Datetime?
- 13. cómo preasignar memoria para un objeto std :: string?
- 14. ¿Cómo puedo codificar una cadena para HTML?
- 15. Cómo analizar una cadena en un objeto DateTime en Perl?
- 16. En Perl, ¿cómo puedo asegurarme de que una cadena corresponde a una fecha válida?
- 17. ¿Cómo puedo escribir en mayúscula la primera letra de cada palabra en una cadena en Perl?
- 18. ¿Cómo extraer un número de una cadena en Perl?
- 19. Cómo convertir una cadena codificada en hexadecimal a una cadena de bytes en Perl?
- 20. ¿Cómo reemplazar una cadena en un archivo existente en Perl?
- 21. ¿Cómo puedo sustituir con una expresión evaluada en Perl?
- 22. ¿Cómo puedo contar personajes en Perl?
- 23. ¿Cómo puedo dividir una cadena en trozos de dos caracteres cada uno en Perl?
- 24. En Perl, ¿cómo puedo llamar a un método cuyo nombre tengo en una cadena?
- 25. ¿Cómo puedo llamar un nombre de función definido en una cadena literal en perl?
- 26. ¿Cómo puedo hacer una referencia a una subrutina de Perl?
- 27. ¿Cómo puedo generar slugs URL en Perl?
- 28. ¿Cómo obtengo la longitud de una cadena en Perl?
- 29. Perl Inline :: Módulo Python, cómo poner código en una cadena
- 30. ¿Cómo puedo pasar una matriz a una función en Perl?
Aunque cada elemento de la matriz crea un SV con todos sus gastos generales. Usará mucha más memoria de esta manera. –