运行时性能应该没有差异如果两种情况下的结果代码相同。然而,这通常是不可能的,除非您使用字符串eval 来创建您的子例程。比如你提供的代码:
... = sub { $_[0]->{$a} };
将比您手动编写的代码慢一点:
sub foo { $_[0]->{'foo'} }
只是因为前者必须先获取变量 $a 的值,然后才能将其用作散列的键,而后者则使用常量作为其散列键。另外,顺便说一句,shift 通常比$_[0] 快。这是一些基准代码:
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 },
});
以及我系统上的结果:
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% --
它们非常接近,以至于差异可能会在噪音中消失,但经过多次试验,我认为您会发现“手动换档”变体是最快的。但与所有像这样的微基准测试一样,您必须在您的硬件和您的 perl 版本上测试您的确切场景以确保任何事情。
这里还有字符串 eval。
eval "sub eval_index { \$_[0]->{'$attr'} }";
eval "sub eval_shift { shift->{'$attr'} }";
它应该与“手动”变体完全相同,加上或减去统计噪音。我的结果:
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% --
同样,这些都非常接近,以至于您必须付出巨大的努力并进行多次试验才能从噪音中挑选出信号。但是使用常量作为散列键和使用变量(必须首先检索其值)作为散列键之间的区别应该显示出来。 (shift 优化是一个单独的问题,更有可能在 perl 的过去或未来版本中以一种或另一种方式改变。)