基准测试子程序签名
子程序签名将在几天内发布到Perl核心。但它们的性能与传统方法(如直接变量赋值和Method::Signatures模块)相比如何?我对所有三个进行了基准测试,结果很有趣。
背景
我介绍了新子程序签名功能,当它们首次出现在Perl开发版本5.19.9中时。对于这些基准测试,我使用了最新的Perl开发版本(5.19.11)。
方法
所有基准测试都来自以下代码的变体
use strict;
use warnings;
use Benchmark::Forking 'cmpthese';
use feature 'signatures';
no warnings 'experimental::signatures';
use Method::Signatures;
sub native_assignment {
die "Too few arguments for subroutine $!" unless @_ == 1;
my ($var) = @_;
}
sub native_signature ($var) {}
func method_signature ($var) {}
cmpthese(-5, {
native_assignment=> sub { native_assignment(1)},
native_signature => sub { native_signature(1) },
method_signature => sub { method_signature(1) },
});
代码首先导入必要的库。行“no warnings ‘experimental::signatures’阻止Perl警告使用子程序签名。然后,代码声明了我们要测试的三个子程序:一个是正常的变量赋值,一个是本地子程序签名,另一个是Method::Signatures(“func”)。
由于基准测试模块按字母顺序执行测试,因此每个基准测试都运行了三次,每次测试重命名一次以更改测试顺序(每个测试在三个基准测试中都是第一次、第二次和第三次运行)。
结果
运行此基准测试返回以下结果
native_signature | method_signature | native_assignment | |
---|---|---|---|
native_signature | -- | -10% | -27% |
method_signature | 12% | -- | -19% |
native_assignment | 38% | 23% | -- |
结果显示本地子程序签名比Method::Signatures函数慢约12%,比本地赋值子程序慢38%。这是干净的语法的代价吗?实际上,这并不是全部的故事。
更改变量的数量
更改子程序中分配的变量数量会影响三种子程序类型的相对性能吗?我重新运行了基准测试,但这次增加要分配的变量数量,并绘制了结果
结果显示,增加变量的数量提高了本地子程序签名相对于Method::Signatures的相对速度。对于两个变量赋值,它们的速度大致相同。对于三个或更多变量,本地子程序签名表现更好,快18%。当我与Ricardo Signes讨论这些结果时,他证实了本地子程序签名代码已经针对多个变量赋值进行了优化,这与上述结果显示相关。
更快的子程序签名
可以认为本地子程序签名已经足够快,并且与变量赋值和Method::Signatures相比提供了几个优点。然而,Ricardo确实与我分享了一个使子程序签名运行得更快的技巧,我忍不住要分享。
将匿名贪婪参数(“@”)添加到子程序签名中,移除了可以传递给子程序的最大参数数量的限制。让我们在我们的基准测试代码中将贪婪参数添加到子程序签名中。我还更新了代码以接受两个参数 - 在以前Method::Signatures和子程序签名表现相似的性能级别
use strict;
use warnings;
use Benchmark::Forking 'cmpthese';
use feature 'signatures';
no warnings 'experimental::signatures';
use Method::Signatures;
sub native_assignment {
die "Too few arguments for subroutine $!" unless @_ == 2;
my ($var1, $var2) = @_;
}
sub native_signature ($var1, $var2, @) {}
func method_signature ($var1, $var2) {}
cmpthese(-5, {
native_assignment=> sub { native_assignment(1, 2)},
native_signature => sub { native_signature(1, 2) },
method_signature => sub { method_signature(1, 2) },
});
以下是结果
method_signature | native_signature | native_assignment | |
---|---|---|---|
method_signature | -- | -23% | -37% |
native_signature | 30% | -- | -18% |
native_assignment | 60% | 23% | -- |
通过添加贪婪参数,本地子程序签名的性能提高了30%!这是因为子程序不再需要运行一个变量计数检查,以检查签名接受的变量的上限。您可以选择是否为了性能提升而移除此检查 - 我想不出一个值得这样做的情况,但谁又知道呢。
结论
子例程变量分配是一种相对低成本的运算,不太可能成为代码运行时间的瓶颈。然而,速度基准测试表明,通过切换到子例程签名不太可能导致性能下降,在某些情况下甚至可以提升运行速度。所以请放心使用它们!
谢谢
感谢Perl大牛Ricardo Signes为我们提供了关于子例程签名实现和slury参数优化的详细信息。
喜欢这篇文章吗?请帮助我们,在微博上分享吧!
*编辑:文章代码和基准测试于2014/05/12进行了针对单个变量分配的修正*
本文最初发布在PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?请通过在GitHub上打开问题或提交拉取请求来帮助我们。
- More commenting... maybe?
github.polettix.it - Perl Weekly Challenge 121: Invert Bit
blogs.perl.org - Web nostalgia: MojoX::Mechanize
github.polettix.it - On the eve of CPAN Testers
blogs.perl.org - PWC121 - The Travelling Salesman
github.polettix.it - PWC121 - Invert Bit
github.polettix.it - Floyd-Warshall algorithm implementations
github.polettix.it - Perl Weekly Challenge 120: Swap Odd/Even Bits and Clock Angle
blogs.perl.org - How I Uploaded a CPAN Module
blogs.perl.org - App::Easer released on CPAN
github.polettix.it