Perl中三元运算符的优化

Perl中三元运算符的优化,perl,loops,optimization,ternary-operator,Perl,Loops,Optimization,Ternary Operator,我有一个循环: for my $line (split /\n/, $content) { ($line !~ /^\-{2,}$/) ? ( $return .= "$line\n" ) : ( $return .= "\N{ZERO WIDTH SPACE}$line\n" ); } 大多数情况下会有与正则表达式不匹配的行(即:大多数情况下,条件都是真的) 我首先使用=~操作符编写了条件(交换了两条条件指令),但这是第二条指令,大

我有一个循环:

for my $line (split /\n/, $content) {
    ($line !~ /^\-{2,}$/) ? ( $return .= "$line\n" )
                          : ( $return .= "\N{ZERO WIDTH SPACE}$line\n" );
}
大多数情况下会有与正则表达式不匹配的行(即:大多数情况下,条件都是真的)

我首先使用
=~
操作符编写了条件(交换了两条条件指令),但这是第二条指令,大多数情况下都会执行

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

当您有一个测试,您知道它将在99%的情况下选择一个分支时,它是否会改变某些东西(性能)以首先使用该分支编写它

在简单的if/else情况下(即三元运算符),答案是no。分支的顺序并不重要,条件将在每次运行时选择下一个分支

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

如果一个If/else选择对读者最有意义的顺序,这通常意味着避免否定
$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) }
};

你可能会想,在
的链条中,如果。。。埃尔西夫。。。埃尔西夫。。。否则,以概率递减的顺序编写测试是最有效的。这将最大限度地减少预期的测试次数,并将产生更快的代码。但是在你的例子中,你只有一个测试,所以它已经被分类了,并且反转测试的逻辑是不相关的

在任何情况下,你担心的细节太细,无法产生任何重大影响。您应该始终将所有代码编写为尽可能的清晰可读

只有一次完成编写和调试代码时,你甚至应该考虑性能。大多数情况下,您的运行时间会足够快,而且,因为您是为了可读性而编写的,所以它也具有高度的可维护性

如果您的代码需要优化,那么您应该首先对其进行分析,以找到瓶颈。我从来没有发现把条件的意义倒置有任何用处。无论您使用哪种语言,我都认为分支和无分支之间的区别是微不足道的

我更希望看到更地道的Perl。除了像我在上面的评论中写的那样逐行读取您的文件外,我还将使用默认变量
$\ucode>并独立于行的其余部分添加零宽度空间

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

那些帕伦夫妇是不必要的,他们让事情看起来更像是在发生。没有它们阅读起来更容易。大概您已经通过修改
$/
将整个文件读入了
$content
?如果是这样的话,您也可以保持原样,逐行读取文件。这还有一个优点,即您不需要将换行符添加回每个输出行的末尾。正则表达式模式中的连字符
-
不需要转义。请不要使用三元运算符作为写入
if
的替代方法。运算符返回一个值,因此请使用它<代码>$return.=expr?“$line\n”:“\n{零宽度空间}$line\n”在较低级别的语言中,由于CPU缓存未命中,可能会有差异。但是对于像Perl这样的重语言,这不再是一个factor.Thx。有了你的代码,我不会失去EOL吗?斯普利特保存了它吗?@Stéphane:我道歉;我离一台工作的电脑不近,所以我无法测试我的代码。现在已经修复了,但是如果直接从文件句柄以
方式读取行,而直接从
循环,则会简单得多。目前,您正在制作文件的多个副本。my$re=qr/^-{2,}$/o;my$return=join“\n”,map{$\n=“\n{ZERO-WIDTH SPACE}”。$\if$\u=~$re;}split(/\n/,$content)@JiriKlouda:如果你想提供一个解决方案,那么你应该发布你自己的答案。这不是对我的解决方案的合法评论,而且代码在评论中几乎不可读。另外,
/o
修饰符很长一段时间以来都是不必要的,而且不管怎样,您的正则表达式模式不包含任何变量。@Stéphane可能是,但我很怀疑。与C++不同,Perl不编译成机器指令。它有自己的VM操作码。Perl必须已经从一个操作码跳到另一个操作码,因此优化一个分支对另一个分支没有多大好处。有关内部构件的更多信息,请参阅和。
for ( split /\n/, $content ) {
    $return .= "\N{ZERO WIDTH SPACE}" if /^-{2,}$/;
    $return .= "$_\n";
}