我花了很长时间才使用警告;严格在Perl,但现在我做了,我看到了优势。
我还不确定的一件事是何时定义一个临时变量。这似乎是一件微不足道的事情,但我运行了很多蒙特卡罗模拟,其中失去一点时间加起来超过10000次迭代。我一直懒得在更快的模拟上使用严格/警告,但它们变得更加复杂,所以我真的需要。
所以(切掉代码来计算东西)我想知道是否
sub doStuff
{
my $temp;
for my $x (1..50)
{
$temp = $x**2;
}
for my $x (1..50)
{
$temp = $x**3;
}
}
或者
sub doStuff
{
for my $x (1..50)
{
my $temp = $x**2;
}
for my $x (1..50)
{
my $temp = $x**3;
}
}
效率更低/更高,或者如果违反了一些我还不知道的Perl编码。
答案 0 :(得分:6)
这两者之间的效率足够接近,并且与任何实际处理相比都相形见绌。所以我会通过代码 - 如果$tmp
确实是临时的并且在循环之后不需要,那么由于所有其他原因,最好将其保持在内部(作用域)。
由于这是关于优化的,我想离题。这些微问题可能会产生影响。但是,您真正获得的地方首先是算法级别,然后适当选择数据结构和技术。低级调整是最后要考虑的事情,并且通常有语言功能和库使它们无关紧要。也就是说,人们应该知道一个人的工具而不是浪费时间。
此外,代码清晰度和效率之间通常需要权衡。如果是这样,我建议编码的正确性和清晰度。然后,如果需要,谨慎和逐步地进行分析和优化,并在两者之间进行大量测试。
这是一个比较,作为核心模块Benchmark的基本用法示例。我抛出一个额外的操作,并添加其他没有临时的情况。
use warnings 'all';
use strict;
use Benchmark qw(cmpthese);
my $x;
sub tmp_in {
for (1..10_000) {
my $tmp = 2 * $_;
$x = $tmp + $_;
}
return $x;
}
sub tmp_out {
my $tmp;
for (1..10_000) {
$tmp = 2 * $_;
$x = $tmp + $_;
}
return $x;
}
sub no_tmp {
for (1..10_000) { $x = 2 * $_ + $_ }
return $x;
}
sub base {
for (1..10_000) { $x += $_ }
return $x;
}
sub calc {
for (1..10_000) { $x += sin sqrt(rand()) }
return $x;
}
cmpthese(-10, {
tmp_in => sub { tmp_in },
tmp_out => sub { tmp_out },
no_tmp => sub { no_tmp },
base => sub { base },
calc => sub { calc },
});
输出(在v5.16上)
Rate calc tmp_in tmp_out no_tmp base calc 623/s -- -11% -26% -44% -59% tmp_in 698/s 12% -- -17% -37% -54% tmp_out 838/s 34% 20% -- -25% -44% no_tmp 1117/s 79% 60% 33% -- -26% base 1510/s 142% 116% 80% 35% --
所以他们不同,显然是循环中的声明成本。但是tmp
版本在列表中。而且,这通常只是开销,所以它被夸大了。还有其他方面 - 例如no_tmp
在一个语句中运行。只有当您的处理主要是迭代时,这些事情才有意义。仅生成(高质量)伪随机数是昂贵的。
这可能在不同的硬件和软件版本之间(疯狂地)也不同。我在更好的机器上使用v5.10的结果有点不同。将样本“计算”替换为您的处理,并在实际硬件上运行,以获取是否重要的相关度量。
答案 1 :(得分:4)
我个人会将临时变量保留在for循环中。仅仅因为它是使用它的地方。另一方面,在某个时候,它会回来咬你(或者那个必须拿起代码的人)意外的价值。
同样premature optimization是anti-pattern
优化可能会降低可读性并添加仅用于的代码 提高性能。这可能使程序或系统复杂化, 使它们更难维护和调试。结果,优化 或者性能调整通常在开发结束时执行 阶段。
答案 2 :(得分:2)
如果你这样做:
for my $x ( 1 .. 50 ){
my $temp = $x**2;
}# $temp goes out of scope
在for循环之后,$ temp将超出范围。 这基本上意味着它不再存在。
如果你这样做:
my $temp;
for my $x ( 1 .. 50 ){
$temp = $x**2;
}# $temp is now 50**2;
$ temp将在子程序范围内, 并且可以在以后更改或返回。
请查看variable scoping in perl了解详情。
我同意上述海报,您应该将变量保留在使用它们的范围内。这样你就更清楚了,以及其他人稍后阅读你的代码,变量是什么,并且当它仍然保持以前的值时,你不会得到与假设它是空的相关的错误。
如果你需要更快的速度,可以考虑升级perl - 例如,perl 5.24有一些不错的性能提升,远远超过一些保存的变量。
您应该只在代码工作后进行优化,并且只在实际帮助的地方进行优化,您可以通过基准测试找到它(例如使用Benchmark)。