No debería haber ninguna diferencia en el rendimiento en tiempo de ejecución si el código resultante es la misma en ambos casos. Sin embargo, esto generalmente no es posible, a menos que use la cadena eval
para crear sus subrutinas. Por ejemplo, el código que proporciona:
... = sub { $_[0]->{$a} };
habrá siempre tan ligeramente más lento que el código que habría escrito manualmente:
sub foo { $_[0]->{'foo'} }
simplemente porque el primero tiene que obtener el valor de la variable $ a antes de usarlo como una clave para el hash, mientras que el último usa una constante como su clave hash. Además, como un lado, shift
generalmente tiende a ser más rápido que $_[0]
.Aquí hay un código de referencia:
use Benchmark qw(cmpthese);
package Foo;
sub manual_shift { shift->{'foo'} }
sub manual_index { $_[0]->{'foo'} }
my $attr = 'foo';
*dynamic_shift = sub { shift->{$attr} };
*dynamic_index = sub { $_[0]->{$attr} };
package main;
my $o = bless { foo => 123 }, 'Foo';
cmpthese(-2, {
manual_shift => sub { my $a = $o->manual_shift },
manual_index => sub { my $a = $o->manual_index },
dynamic_shift => sub { my $a = $o->dynamic_shift },
dynamic_index => sub { my $a = $o->dynamic_index },
});
y los resultados en mi sistema:
Rate dynamic_index manual_index dynamic_shift manual_shift
dynamic_index 1799024/s -- -3% -4% -7%
manual_index 1853616/s 3% -- -1% -4%
dynamic_shift 1873183/s 4% 1% -- -3%
manual_shift 1937019/s 8% 4% 3% --
Están tan cerca que las diferencias pueden perderse en el ruido, pero a lo largo de muchos ensayos creo que se verá que la variante del "cambio manual" es la más rápida. Pero como con todos los microbenchmarks como este, tienes que probar tu escenario exacto en tu hardware y tu versión de Perl para estar seguro de cualquier cosa.
Y aquí está la eval de cadena arrojada a la mezcla.
eval "sub eval_index { \$_[0]->{'$attr'} }";
eval "sub eval_shift { shift->{'$attr'} }";
Debe ser exactamente igual a las variantes "manuales", más o menos el ruido estadístico. Mis resultados:
Rate dynamic_index manual_index dynamic_shift manual_shift eval_shift eval_index
dynamic_index 1820444/s -- -1% -2% -3% -4% -5%
manual_index 1835005/s 1% -- -1% -2% -3% -4%
dynamic_shift 1858131/s 2% 1% -- -1% -2% -3%
manual_shift 1876708/s 3% 2% 1% -- -1% -2%
eval_shift 1894132/s 4% 3% 2% 1% -- -1%
eval_index 1914060/s 5% 4% 3% 2% 1% --
Una vez más, estos son todos tan cerca que habría que tomar grandes dolores y realizar muchas pruebas para ordenar la señal del ruido. Pero la diferencia entre usar una constante como una clave hash y usar una variable (cuyo valor primero debe recuperarse) como una clave hash debería mostrarse a través de. (La optimización shift
es un problema aparte y es más probable que cambie de una forma u otra en versiones pasadas o futuras de perl.)
'* {" get_ $ a "} = sub' ... también debería funcionar. (No es necesario tener '__PACKAGE__' allí) –