Perl:为什么if语句比" and"慢?
在Perl中,条件可以表示为
if (condition) { do something }
或者作为
(condition) and do { do something }
有趣的是,第二种方法似乎要快10%。有人知道为什么吗?
解决方案
我已经失望了,它真的不应该更快。第一个的操作码树是
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"
我真的不知道后者怎么会更快。它还有更多的操作码!
根据基准,第二个稍微慢一些。可能与条件有关,但这是一个非常简单的情况的结果:
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)
这只是说明,如果我们不知道如何执行正确的代码配置文件,请不要执行此操作。这两种方法的速度差异在相同的Big O()速度之内(如@Leon Timmermans操作码分析所证明的那样),基准测试只是根据其他局部条件(不一定是代码)显示差异。
@Svante说" and"更快,@ shelfoo说" if"更快。
我的意思是真的……在一千万次循环中,百分之七十分之一秒的变化?从统计上讲,这不是更快或者更慢。
与其关注这种微小的时序,不如了解代码重构和Big O()表示法……如何减少代码中的循环次数……以及最重要的是,如何使用代码探查器查看真正的代码在哪里。瓶颈。不用担心统计上无关紧要的东西。 ;)
在平均之前,我们进行了多少次测试?在统计上,非常非常小的偏差是很小的!有很多原因可以使速度在测试之间略有不同。
有关以下内容的一些评论:
首先,不要使用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
它还可能取决于Perl的版本。我们还没有提到。而且无论如何,差异还不足以担心。因此,使用更有意义的方法。