Perl中三元运算符的优化

Optimization of the ternary operator in Perl

我有这个循环:

for my $line (split /\n/, $content) {
    ($line !~ /^\-{2,}$/) ? ( $return .= "$line\n" )
                          : ( $return .= "\N{ZERO WIDTH SPACE}$line\n" );
}

大部分行与正则表达式不匹配(即:大多数情况下条件为真)。

我首先使用 =~ 运算符编写了条件(交换了两个条件指令),但这是 second 指令最常执行的的时代。

换句话说......当你有一个测试,你知道它会在 99% 的情况下选择一个分支,它会改变一些东西(性能)来写它首先用那个分支吗?

When you have a test which you know that it will choose one branch in 99% of the cases, does it change something (performance) to write it with that branch first?

在简单的 if/else 情况下(即三元运算符),答案是 。分支的顺序无关紧要,条件每次都会运行并选择要走的分支。

在 if/elsif/else 的情况下,这很重要,因为有多个条件 运行。将最常见的情况放在第一位会使事情变得更快。

如果 if/else 选择对 reader 最有意义的顺序,这通常意味着避免否定。 $line =~ /^\-{2,}$/$line !~ /^\-{2,}$/ 更易读。 $line =~ /^-{2,}$/ 更好(不需要在正则表达式中转义 -)。

至少应该没关系。对于任何像 Perl 这样复杂的东西,最好对这些东西进行基准测试。想出一些可以充分锻炼 CPU 的东西,以免在正常的基准测试抖动中丢失,这有点麻烦。在得出结论之前,请务必运行多次迭代并进行大量迭代。

use strict;
use warnings;
use v5.10;

use Benchmark qw(cmpthese);

my $Iterations = shift;

my $Threshhold = 100_000;

# I've picked something that isn't constant to avoid constant folding
sub a_then_b {
    my $num = shift;
    return $num > $Threshhold ? sqrt($num) + sqrt($num) ** 2
                              : $num + $num;
}

sub b_then_a {
    my $num = shift;
    return $num <= $Threshhold ? $num + $num
                               : sqrt($num) + sqrt($num) ** 2;
}

say "First one side";
cmpthese $Iterations, {
    a_then_b => sub { a_then_b($Threshhold - 1) },
    b_then_a => sub { b_then_a($Threshhold - 1) }
};

say "Then the other";
cmpthese $Iterations, {
    a_then_b => sub { a_then_b($Threshhold + 1) },
    b_then_a => sub { b_then_a($Threshhold + 1) }
};

最后一点,要充分利用三元组,赋值应该放在左侧。三元returns其分支的结果。

$return .= $line =~ /^-{2,}$/ ? "\N{ZERO WIDTH SPACE}$line\n"
                               : "$line\n";

您可能会想到,在 if ... elsif ... elsif ... else 链中,如果测试按概率降序编写,效率最高。这最大限度地减少了预期的测试次数,并且应该会产生更快的代码。但在您的情况下,您只有一个测试,因此它已经排序,并且反转该测试的逻辑是无关紧要的。

在任何情况下,您都担心细节过于精细而无法产生任何显着差异。您应该始终将所有代码编写为清晰可读尽可能

只有在您完成代码的编写和调试之后,您才应该考虑性能。大多数情况下,您的 运行 时间会足够快,而且由于您是为了可读性而编写的,因此它也将是高度可维护的

如果您的代码需要优化,那么您应该首先分析它以找到瓶颈。我发现 never 完全没有任何用处。无论您使用哪种语言,我都希望分支和无分支之间的区别微不足道

我希望看到更多地道的 Perl。除了像我在上面的评论中写的那样逐行阅读你的文件,我会使用默认变量 $_ 并添加你的 零宽度 space 独立于该行的其余部分

for ( split /\n/, $content ) {
    $return .= "\N{ZERO WIDTH SPACE}" if /^-{2,}$/;
    $return .= "$_\n";
}