我通常不使用输出参数(参数充当输入和输出值或仅输出)。这是为了提高我的代码的可读性和可维护性。但是,再一次,我突然有了一个深深嵌套的子程序调用。我发现自己试图优化它以获得一些速度提升。
这是一个例子:我有一个字符串表示从文件读取的空白修剪线。如果该行为空,我想用代表返回键的unicode符号替换它。假设我在谷歌搜索,发现符号↵
(统一码U+21B5
)看起来不错[1]。所以我写了一个简短的子程序:
sub handle_empty_lines {
my ($str) = @_;
if ((!defined $str) || $str eq '') {
return "\x{21B5}";
}
return $str;
}
,我用它像这样:
$line = handle_empty_lines($line);
现在,我想优化这个电话,但仍然有代码具有可读性和可维护性。
第一个选择是把它内联:
$line = "\x{21B5}" if (!defined $str) || $str eq '';
当然是天然的和快速的,但是让我们假设我不想if语句,拒绝参与这个选项杂乱的代码。
下面是另外两个选项,
传递一个参考
$str
以避免在子程序复制输入参数(即:转换呼叫按值来调用按引用),或利用Perl的内置调用引用机制。
两个选项引入了一个"input/output argument"
(即:作为输入和输出的参数),并因此降低了代码的可读性和使维护更困难的(在我的意见)。
让第三个选项保留原始版本(按值)。以下是速度的三个选项(不可读性)的快速比较。
use strict;
use warnings;
use Benchmark qw(timethese);
my $str1 = '';
timethese(
2_000_000,
{
case1 => sub { my $test = $str1; case1(\$test) },
case2 => sub { my $test = $str1; case2($test) },
case3 => sub { my $test = $str1; $test = case3($test) },
}
);
sub case1 {
if ((!defined $$_[0]) || $$_[0] eq '') {
$$_[0] = "\x{21B5}";
}
}
sub case2 {
if ((!defined $_[0]) || $_[0] eq '') {
$_[0] = "\x{21B5}";
}
}
sub case3 {
my ($str) = @_;
if ((!defined $str) || $str eq '') {
return "\x{21B5}";
}
return $str;
}
输出(Ubuntu的笔记本电脑,英特尔(R)核心(TM)i7-4702MQ CPU @ 2.20GHz):
Benchmark: timing 2000000 iterations of case1, case2, case3...
case1: 1 wallclock secs (0.84 usr + 0.00 sys = 0.84 CPU) @ 2380952.38/s (n=2000000)
case2: 1 wallclock secs (0.45 usr + 0.00 sys = 0.45 CPU) @ 4444444.44/s (n=2000000)
case3: 1 wallclock secs (0.70 usr + 0.00 sys = 0.70 CPU) @ 2857142.86/s (n=2000000)
注意,壳体2是87%速度比情况1,比情况3快56%。
有趣的是,引用调用(情况1)比调用值(情况3)慢。
问:
想我现在想保持的情况下2:
sub handle_empty_lines {
if ((!defined $_[0]) || $_[0] eq '') {
$_[0] = "\x{21B5}";
}
}
然后,如果我把它用:
handle_empty_lines($line);
它没有给线索读者修改$line
。
我该如何处理?我能想到的两个选项:
发出呼叫后评论:子程序
handle_empty_lines($line); # Note: modifies $line
更改名称。给一个名字,让指示给 读者
$line
被修改,如:handle_empty_lines__modifies_arg($line);
脚注:
1.我后来发现,我可以用N{}
转义以使代码更易于使用“\ N {DOWNWARDS ARROW WITH CORNER LEFTWARDS}”而不是“\”
2.对于这个简单的情况下,我同意这是有问题的,如果这可以被称为任何形式的杂波..
3. 4444444.44/2380952.38 = 1.87
请注意,情况2比情况1快87%3,比情况3快56%。*“,如果您使用'cmpthese'而不是'timethese', – ikegami
@ikegami是的,我考虑过使用'cmpthese',但是我发现这些数字让我困惑。 –
你的每个函数都与其他函数有两种不同。缺少:'sub case4 if((!defined $ _ [0])|| $ _ [0] eq''){ return“\ x {} {}}; } return $ _ [0]; }' – ikegami