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";
}