使用反射时性能中断$ foo - > $ bar()

Rob*_*ert 5 reflection perl performance

我想知道当我使用反射来调用一个名为i的字符串的方法时会发生什么:

my $foo = Foo->new();
my $method = 'myMethod';
$foo->$method();
Run Code Online (Sandbox Code Playgroud)

比原生呼叫慢约20%:

$foo->myMethod();
Run Code Online (Sandbox Code Playgroud)

有关如何实现perl反射的文档的任何指针都会有所帮助.

谢谢.

Eri*_*rom 10

> perl -MO=Concise -e '$foo->$bar'
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
7     <1> entersub[t3] vKS/TARG ->8
3        <0> pushmark s ->4
-        <1> ex-rv2sv sKM/1 ->5
4           <#> gvsv[*foo] s ->5
6        <1> method K/1 ->7             # ops to read $bar and then call method
-           <1> ex-rv2sv sK/1 ->6       # 
5              <#> gvsv[*bar] s ->6     # 
-e syntax OK

> perl -MO=Concise -e '$foo->bar'
7  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
6     <1> entersub[t2] vKS/TARG ->7
3        <0> pushmark s ->4
-        <1> ex-rv2sv sKM/1 ->5
4           <#> gvsv[*foo] s ->5
5        <$> method_named[PV "bar"] ->6   # op to call the 'bar' method
-e syntax OK
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,perl必须加载$bar变量,然后检查它是否包含可用作方法的名称或值.由于$bar调用之间的内容可能会发生变化,因此必须每次都进行此查找.

在第二个示例中,perl已经知道该字符串"bar"应该用作方法名称,因此这可以避免在每次执行时加载变量并检查其内容.

但是你不应该太担心两个本地操作之间20%的速度差异.主要是因为本机操作非常快,并且它们实际需要的任何速度很快就会被代码必须执行的实际算法相形见绌.换句话说,除非您将此问题视为代码分析器的热点,否则速度差异具有更多的教学意义而非实际重要性.


ike*_*ami 4

首先,我不相信我没有看到的基准。很容易弄错他们。我自己对它们进行了基准测试。

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);
Run Code Online (Sandbox Code Playgroud)

我可以复制你的结果。

     Rate   rt   ct
rt 1879/s   -- -19%
ct 2333/s  24%   --

(Rate is 1/1000th of actual rate.)
Run Code Online (Sandbox Code Playgroud)

这看起来确实相当大,但百分比可能会因为如此快的速度而产生误导。让我们看看绝对时间的差异。

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.
Run Code Online (Sandbox Code Playgroud)

没有那么多。那么这些时间都花在哪里了呢?

$ 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
Run Code Online (Sandbox Code Playgroud)

似乎唯一的区别是额外的符号表查找。100ns 似乎有点过分了。但可以肯定的是,与一些微小的东西相比,比如添加一个。

$ 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
Run Code Online (Sandbox Code Playgroud)

将该代码插入our $x = 100;上面的基准代码中,我们得到

            Rate addition  baseline
addition  4839/s       --      -26%
baseline  6532/s      35%        --

(Rate is 1/1000th of actual rate.)
Run Code Online (Sandbox Code Playgroud)

所以,

Basline:    6553000/s = 153 nanoseconds per assignment
Addition:   4839000/s = 207 nanoseconds per assignment+addition
Difference:              54 nanoseconds per addition
Run Code Online (Sandbox Code Playgroud)

那么简单的符号表查找花费的时间是加一的两倍是否合理?可能是,因为它涉及对字符串进行哈希处理并在短链表中查找字符串。

你真的介意到处多花 100 纳秒吗?不,我猜。