Pregunta

A menudo tengo una subrutina en Perl que llena una matriz con información.Como también estoy acostumbrado a hackear en C++, a menudo lo hago así en Perl, usando referencias:

my @array;
getInfo(\@array);

sub getInfo {
   my ($arrayRef) = @_;
   push @$arrayRef, "obama";
   # ...
}

en lugar de la versión más sencilla:

my @array = getInfo();

sub getInfo {
   my @array;
   push @array, "obama";
   # ...
   return @array;
}

La razón, por supuesto, es que no quiero que la matriz se cree localmente en la subrutina y luego se copie al regresar.

¿Está bien?¿O Perl optimiza eso de todos modos?

¿Fue útil?

Solución

¿Qué hay de devolver una referencia a un array en el primer lugar?

sub getInfo {
  my $array_ref = [];
  push @$array_ref, 'foo';
  # ...
  return $array_ref;
}

my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};

Editar acuerdo con el comentario de dehmann:

También es posible usar una matriz de lo normal en la función y devolver una referencia a la misma.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return \@array;
}      

Otros consejos

referencias de paso es más eficiente, pero la diferencia no es tan grande como en C ++. El argumento de los propios valores (que significa: los valores de la matriz) siempre se pasan por referencia de todos modos (valores devueltos se copian sin embargo)

.

La pregunta es: ¿qué importa? La mayoría de las veces, no lo hace. Si usted está volviendo 5 elementos, no se moleste al respecto. Si usted está volviendo / 100'000 pasando elementos, referencias de uso. Sólo optimizarlo si es un cuello de botella.

Si miro a su ejemplo y pensar en lo que quiere hacer Estoy acostumbrado a escribir de esta manera:

sub getInfo {
  my @array;
  push @array, 'obama';
  # ...
  return \@array;
}

Me parece como versión sencilla cuando necesito volver gran cantidad de datos. No hay necesidad de asignar array fuera sub como escrito en el primer fragmento de código porque my lo haga por usted. De todos modos no se debe hacer la optimización prematura como Leon Timmermans sugieren .

Para responder a la rumiación final, no, Perl no optimiza esta distancia. No puede, en realidad, porque devuelve una matriz y devolver un escalar son fundamentalmente diferentes.

Si se trata de grandes cantidades de datos o si el rendimiento es una preocupación importante, entonces sus hábitos C, serán muy útiles - pass y las referencias a estructuras de datos en lugar de devolver las estructuras mismas de modo que no necesitará copiar. Pero, como Leon Timmermans señaló, la gran mayoría de las veces, se trata con menores cantidades de datos y el rendimiento no es la gran cosa, por lo que hacerlo de cualquier manera que parece más fácil de leer.

Esta es la forma en que normalmente devolver una matriz.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return @array if wantarray;
  return \@array;
}

Esta manera de que funcione de la manera deseada, en escalar o lista de contextos.

my $array = getInfo;
my @array = getInfo;

$array->[0] == $array[0];

# same length
@$array == @array;

No intentaría para optimizarlo a menos que sepa que es una parte lenta de su código. Incluso entonces me gustaría utilizar puntos de referencia para ver qué subrutina es realmente más rápido.

Hay dos consideraciones.La más obvia es ¿qué tan grande será su conjunto?Si se trata de menos de unas pocas docenas de elementos, entonces el tamaño no es un factor (a menos que esté microoptimizando para alguna función llamada rápidamente, pero primero tendría que hacer un perfil de memoria para demostrarlo).

Esa es la parte fácil.La segunda consideración que a menudo se pasa por alto es la interfaz.¿Cómo se utilizará la matriz devuelta?Esto es importante porque la desreferenciación de matrices completas es un poco horrible en Perl.Por ejemplo:

for my $info (@{ getInfo($some, $args) }) {
    ...
}

Eso es feo.Esto es mucho mejor.

for my $info ( getInfo($some, $args) ) {
    ...
}

También se presta para mapeo y grepping.

my @info = grep { ... } getInfo($some, $args);

Pero devolver una referencia de matriz puede ser útil si vas a seleccionar elementos individuales:

my $address = getInfo($some, $args)->[2];

Eso es más simple que:

my $address = (getInfo($some, $args))[2];

O:

my @info = getInfo($some, $args);
my $address = $info[2];

Pero en ese punto, deberías preguntarte si @info es realmente una lista o un hash.

my $address = getInfo($some, $args)->{address};

Lo que no debes hacer es tener getInfo() devuelve una referencia de matriz en contexto escalar y una matriz en contexto de lista.Esto confunde el uso tradicional del contexto escalar como longitud de matriz, lo que sorprenderá al usuario.

Finalmente, conectaré mi propio módulo, Método::Firmas, porque ofrece un compromiso para pasar referencias de matriz sin tener que usar la sintaxis de referencia de matriz.

use Method::Signatures;

method foo(\@args) {
    print "@args";      # @args is not a copy
    push @args, 42;   # this alters the caller array
}

my @nums = (1,2,3);
Class->foo(\@nums);   # prints 1 2 3
print "@nums";        # prints 1 2 3 42

Esto se hace a través de la magia de Datos::Alias.

3 otras mejoras de rendimiento potencialmente grande si usted está leyendo una totalidad, un archivo bastante grande y cortar en una matriz:

  1. Activar el uso del búfer con sysread () en lugar de lectura () (manual advierte acerca de la mezcla)
  2. Pre-extender la matriz valorando el último elemento -     salvaciones asignaciones de memoria
  3. Uso Desempaquetar () para datos como datos del canal de gráficos uint16_t divide rápidamente

La aprobación de un ref matriz para la función permite que el programa principal para hacer frente a una matriz simple, mientras que la función de una sola escritura y olvidar trabajador utiliza el más complicado "$ @" y la flecha -> [$ II] Las formas de acceso. Siendo bastante C'ish, es probable que sea rápido!

No sé nada de Perl por lo que esta es una respuesta del idioma.

Es, en cierto sentido, ineficaz para copiar una matriz de un subprograma en el programa de llamada. La ineficiencia surge en la memoria adicional utilizada y el tiempo necesario para copiar los datos de un lugar a otro. Por otra parte, para todos, pero las matrices más grandes, es posible que no le importa un comino, y lo prefiere, puede copiar matrices a cabo por la elegancia, terquedad o cualquier otra razón.

La solución eficiente es para la subrutina para pasar el programa de llamada la dirección de la matriz. Como digo, no tengo ni idea sobre el comportamiento predeterminado del Perl a este respecto. Sin embargo, algunos lenguajes proporcionan al programador la opción de elegir qué enfoque.

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