Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 使用反射时的性能中断$foo->$bar()_Performance_Perl_Reflection - Fatal编程技术网

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

Performance 使用反射时的性能中断$foo->$bar(),performance,perl,reflection,Performance,Perl,Reflection,我想知道当我使用反射调用一个名称为字符串的方法时,会发生什么: my $foo = Foo->new(); my $method = 'myMethod'; $foo->$method(); 比本机呼叫慢约20%: $foo->myMethod(); 任何指向如何实现perl反射的文档的指针都会很有帮助 谢谢。>perl-MO=concrete-e'$foo->$bar' > perl -MO=Concise -e '$foo->$bar' 8 <@&g

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

my $foo = Foo->new();
my $method = 'myMethod';
$foo->$method();
比本机呼叫慢约20%:

$foo->myMethod();
任何指向如何实现perl反射的文档的指针都会很有帮助

谢谢。

>perl-MO=concrete-e'$foo->$bar'
> 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
8离开[1参考]vKP/REFC->(结束) 1输入->2 2下一状态(主1-e:1)v:{->3 7输入Sub[t3]vKS/TARG->8 3推动标记s->4 -ex-rv2sv sKM/1->5 4 gvsv[*foo]s->5 6方法K/1->7#操作读取$bar,然后调用方法 -ex-rv2sv sK/1->6# 5 gvsv[*巴]s->6# -e语法正常 >perl-MO=简明-e'$foo->bar' 7离开[1参考]vKP/REFC->(结束) 1输入->2 2下一状态(主1-e:1)v:{->3 6输入Sub[t2]vKS/TARG->7 3推动标记s->4 -ex-rv2sv sKM/1->5 4 gvsv[*foo]s->5 5方法u命名为[PV“bar”]->6方法op调用“bar”方法 -e语法正常
在第一个示例中,perl必须加载
$bar
变量,然后检查它是否包含可以用作方法的名称或值。由于
$bar
的内容可能在调用之间发生更改,因此每次都必须进行此查找

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


但是,您不应该过分担心两个本机操作之间20%的速度差异。这主要是因为本机操作非常快,而且它们实际需要的任何速度都会很快与您的代码必须执行的实际算法相形见绌。换句话说,除非您将此问题与cod隔离为一个热点e profiler,速度差在教学上的重要性大于实际意义。

您可以通过使用方法参考来加快速度,ala:

$metref = \&{"Class::$method"};
$instance = new Class;
$instance->$metref(@args);

如果在编译时知道方法名,显然可以使用
$metref=\&Class::myMethod
哪个perl可能比符号解引用更有效。请参见和。

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

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);
我可以复制你的结果

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

(Rate is 1/1000th of actual rate.)
这看起来确实很大,但是百分比可能会很容易让人误解。让我们看看绝对时间的差异

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.
没有那么多。那么这些时间花在哪里呢

$ 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
所以

那么,一个简单的符号表查找所花费的时间是添加一个符号表的两倍,这合理吗?可能是因为它需要对字符串进行散列,并在短链表中查找字符串


你真的在乎在这里或那里额外花费100纳秒吗?不,我猜。

我认为很明显,它不需要包含对特定方法引用的操作码,而是需要更多的指令来在
@ISA
层次结构的符号链中查找该方法,并在运行时分派到该方法。@Axeman,method diSPATCH是动态的考虑运行时<代码> @ ISA(或符号表)修改,Re> <代码>祝福> /代码> ING对象等。另外,描述方法查找为运行时缓存,最初的脸红表明,探测<代码> @ ISA < /代码>不能解释速度差。最好写<代码>类::->可以($方法)获取coderef。它尊重继承并在严格的条件下工作。而且,
$metref->($instance,@args)
更快。
$ 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
            Rate addition  baseline
addition  4839/s       --      -26%
baseline  6532/s      35%        --

(Rate is 1/1000th of actual rate.)
Basline:    6553000/s = 153 nanoseconds per assignment
Addition:   4839000/s = 207 nanoseconds per assignment+addition
Difference:              54 nanoseconds per addition