Primero, no confío en los puntos de referencia que no veo. Es muy fácil equivocarse. Los comparé yo mismo.
use strict;
use warnings;
use Benchmark qw(cmpthese);
sub new { return bless({}, $_[0]); }
sub myMethod { }
my %tests = (
rt => '$foo->$method() for 1..1000;',
ct => '$foo->myMethod() for 1..1000;',
);
$_ = 'use strict; use warnings; our $foo; our $method; ' . $_
for values(%tests);
our $foo = __PACKAGE__->new();
our $method = 'myMethod';
cmpthese(-3, \%tests);
Puedo replicar los resultados.
Rate rt ct
rt 1879/s -- -19%
ct 2333/s 24% --
(Rate is 1/1000th of actual rate.)
Eso parece bastante grande, pero los porcentajes pueden ser muy engañosos con algo tan rápido. Veamos la diferencia en tiempos absolutos.
Compile-time: 2333000 calls per second = 429 nanoseconds per call
Run-time: 1879000 calls per second = 532 nanoseconds per call
Difference: 103 nanoseconds per call.
No mucho. Entonces, ¿dónde está ese tiempo?
$ perl -MO=Concise,-exec -e'$foo->myMethod()' $ perl -MO=Concise,-exec -e'$foo->$method()'
1 <0> enter = 1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{ = 2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s = 3 <0> pushmark s
4 <#> gvsv[*foo] s = 4 <#> gvsv[*foo] s
+ 5 <#> gvsv[*method] s
5 <$> method_named[PV "myMethod"] ! 6 <1> method K/1
6 <1> entersub[t2] vKS/TARG = 7 <1> entersub[t3] vKS/TARG
7 <@> leave[1 ref] vKP/REFC = 8 <@> leave[1 ref] vKP/REFC
-e syntax OK = -e syntax OK
Parece que la única diferencia es una búsqueda de tablas de símbolos adicionales. 100ns parece excesivo para eso. Pero para estar seguro, compare con algo pequeño, digamos como agregar uno.
$ perl -MO=Concise,-exec -e'my $y = $x;' $ perl -MO=Concise,-exec -e'my $y = $x + 1;'
1 <0> enter = 1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{ = 2 <;> nextstate(main 1 -e:1) v:{
3 <#> gvsv[*x] s = 3 <#> gvsv[*x] s
+ 4 <$> const[IV 1] s
+ 5 <2> add[t3] sK/2
4 <0> padsv[$y:1,2] sRM*/LVINTRO = 6 <0> padsv[$y:1,2] sRM*/LVINTRO
5 <2> sassign vKS/2 = 7 <2> sassign vKS/2
6 <@> leave[1 ref] vKP/REFC = 8 <@> leave[1 ref] vKP/REFC
-e syntax OK = -e syntax OK
tapar ese código y our $x = 100;
en el código de referencia más arriba, obtenemos
Rate addition baseline
addition 4839/s -- -26%
baseline 6532/s 35% --
(Rate is 1/1000th of actual rate.)
Así,
Basline: 6553000/s = 153 nanoseconds per assignment
Addition: 4839000/s = 207 nanoseconds per assignment+addition
Difference: 54 nanoseconds per addition
lo tanto, es razonable para una simple búsqueda en la tabla de símbolos para tomar el doble de siempre y cuando agregue uno? Probablemente, ya que implica hash de una cadena y buscar una cadena en la lista de enlaces cortos.
¿Realmente te importa gastar 100ns extra aquí y allá? No, estoy adivinando.
Creo que es bastante obvio que en lugar de los códigos de operación que contienen la referencia a un método particular, necesita más instrucciones para buscar el método en la cadena de símbolos de la jerarquía '@ ISA' y enviarlo a ese en tiempo de ejecución. – Axeman
@Axeman, el despacho del método es dinámico: considere la modificación del tiempo de ejecución '@ ISA' (o la tabla de símbolos), los objetos que se vuelven a convertir, etc. Además, [' perlobj'] (http://perldoc.perl.org/ perlobj.html) describe la búsqueda de métodos como runtime-cached, que a primera vista sugiere que la prueba '@ ISA' no puede explicar la diferencia de velocidad. – pilcrow