Perl:为什么if语句比“和”慢?

时间:2008-09-17 23:05:00

标签: performance perl

在Perl中,条件可以表示为

if (condition) { do something }

(condition) and do { do something }

有趣的是,第二种方式似乎要快10%左右。有谁知道为什么?

6 个答案:

答案 0 :(得分:18)

关于下面的deparse的一些评论:

首先,不要使用B :: Terse,它已经过时了。一旦习惯,B :: Concise就会为您提供更好的信息。

其次,您使用给定的文字代码运行它,因此条件被视为一个恰好为真的裸字,因此布尔检查在两种情况下都被优化掉了,哪种方法会失败。

第三,没有额外的操作码 - “null”表示已被优化掉的操作码(完全在执行树之外,但仍在解析树中。)

这是两种情况的简明执行树,它们将它们显示为相同:

$ perl -MO=Concise,-exec -e'($condition) and do { do something }'
1  <0> enter 
2  <;> nextstate(main 2 -e:1) v
3  <#> gvsv[*condition] s
4  <|> and(other->5) vK/1
5      <$> const[PV "something"] s/BARE
6      <1> dofile vK/1
7  <@> leave[1 ref] vKP/REFC
-e syntax OK
$ perl -MO=Concise,-exec -e'if ($condition) { do something }'
1  <0> enter 
2  <;> nextstate(main 3 -e:1) v
3  <#> gvsv[*condition] s
4  <|> and(other->5) vK/1
5      <$> const[PV "something"] s/BARE
6      <1> dofile vK/1
7  <@> leave[1 ref] vKP/REFC
-e syntax OK

答案 1 :(得分:11)

我已经贬低了它,它真的不应该更快。第一个的操作码树是

LISTOP (0x8177a18) leave [1] 
    OP (0x8176590) enter 
    COP (0x8177a40) nextstate 
    LISTOP (0x8177b20) scope 
        OP (0x81779b8) null [174] 
        UNOP (0x8177c40) dofile 
            SVOP (0x8177b58) const [1] PV (0x81546e4) "something" 

第二个的操作码树是

LISTOP (0x8177b28) leave [1] 
    OP (0x8176598) enter 
    COP (0x8177a48) nextstate 
    UNOP (0x8177980) null 
        LISTOP (0x8177ca0) scope 
            OP (0x81779c0) null [174] 
            UNOP (0x8177c48) dofile 
                SVOP (0x8177b60) const [1] PV (0x81546e4) "something"

我真的不知道后者如何更快。它做了更多的操作码!

答案 2 :(得分:11)

如果您不知道如何进行正确的代码分析,那么就不要这样做了。这两种方法的速度差异在相同的Big O()速度内(由@Leon Timmermans操作码分析证明) - 基准测试只是根据其他本地条件显示差异,而不一定是您的代码。

@Svante说“和”更快,而@shelfoo说“如果”更快。

我的意思是......千万次循环的变化是7百分之一秒?这不是更快或更慢,从统计学上来说......这是相等的。

不要看这样的微不足道的时间,而是学习代码重构和Big O()表示法...如何减少代码中的循环次数......最重要的是,如何使用代码分析器来查看真正的瓶颈在哪里。不要担心统计上无关紧要的东西。 ;)

答案 3 :(得分:3)

在平均之前你做了多少次测试?非常非常小的偏差在统计上是微不足道的!测试之间的速度差异有很多原因。

答案 4 :(得分:2)

根据Benchmark的说法,第二个稍慢。可能它与条件有关,但这是一个非常简单的结果:


use Benchmark;

timethese(10000000, {
    'if' => '$m=5;if($m > 4){my $i=0;}',
    'and' => '$m=5; $m > 4 and do {my $i =0}',
});

结果:


Benchmark: timing 10000000 iterations of Name1, Name2...
     if:  3 wallclock secs ( 2.94 usr +  0.01 sys =  2.95 CPU) @ 3389830.51/s (n=10000000)
     and:  3 wallclock secs ( 3.01 usr +  0.01 sys =  3.02 CPU) @ 3311258.28/s (n=10000000)

答案 5 :(得分:0)

它还可能取决于Perl的版本。你没有提到过。无论如何,差异还不足以让人担心。所以使用更有意义的东西。