2

Perl では、条件は次のいずれかで表現できます。

if (condition) { do something }

またはとして

(condition) and do { do something }

興味深いことに、2 番目の方法は約 10% 速いようです。誰かが理由を知っていますか?

4

6 に答える 6

18

以下のデパースに関するコメント:

まず、B::Terseを使用しないでください。廃止されました。B :: Conciseは、慣れればはるかに優れた情報を提供します。

次に、指定されたリテラルコードを使用して実行したため、条件はたまたま真のベアワードと見なされたため、どちらの場合もブールチェックが最適化され、目的が果たせなくなりました。

第3に、余分なオペコードはありません。「null」は、最適化されたオペコードを示します(完全に実行ツリーから外れていますが、解析ツリーには残っています)。

2つのケースの簡潔な実行ツリーは、次のとおりです。これらは同一であることが示されています。

$ 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
于 2008-09-18T09:18:35.200 に答える
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" 

2 番目のオペコード ツリーは次のとおりです。

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"

後者がどのように高速になるかは本当にわかりません。オペコードをさらに実行します!

于 2008-09-17T23:17:01.293 に答える
11

適切なコード プロファイリングを行う方法がわからない場合は、このようなことをしないでください。これら 2 つのメソッドの速度の違いは、同じ Big O() 速度内にあります (@Leon Timmermans オペコード分析で証明されているように) - ベンチマークは、必ずしもコードではなく、他のローカル条件に基づいて違いを示すだけです。

@Svante は「and」の方が速いと言い、@shelfoo は「if」の方が速いと言いました。

つまり、1000 万回のループで 700 分の 1 秒の変化ということですか? それは統計的に速くも遅くもありません....それは等しいです。

このようなごくわずかなタイミングを見る代わりに、コードのリファクタリングと Big O() 表記について学び、コード内のループの数を減らす方法と、コード プロファイラーを使用して実際のタイミングを確認する方法を学びます。ボトルネックは。統計的に意味のないものについて心配する必要はありません。;)

于 2008-09-18T03:52:07.700 に答える
3

平均化する前に何回テストを行いましたか? 非常に小さな偏差は、統計的に重要ではありません! テスト間で速度がわずかに異なる理由はたくさんあります。

于 2008-09-18T03:55:06.133 に答える
2

ベンチマークによると、2番目は少し遅いです。おそらくそれは状態と関係がありますが、非常に単純なケースの結果は次のとおりです。


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)

于 2008-09-18T00:35:39.717 に答える
0

また、Perl のバージョンに依存する場合もあります。あなたが言及していないこと。とにかく、その違いは心配するほどではありません。したがって、より意味のあるものを使用してください。

于 2008-09-18T15:34:33.173 に答える