4

次の場合:

$var = 3; // we'll say it's set to 3 for this example
if ($var == 4) {
    // do something
} else if ($var == 5) {
    // do something
} else if ($var == 2) {
    // do something
} else if ($var == 3) {
    // do something
} else {
    // do something
}

80%の$var確率で3であるとすると、本当のケースを見つける前に4つのケースを通過するという事実を心配しますか?

小さなサイトでは大したことではないと思っていますが、ifステートメントが1秒間に数千回実行される場合はどうでしょうか。

私はPHPで作業していますが、言語は関係ないと思います。

4

10 に答える 10

13

これは、私がレーダー システム用のソフトウェアを作成していたときの方法です。(レーダーでは速度が重要です。「リアルタイム」が実際に「高速」ではなく「リアル」を意味する数少ない場所の 1 つです。)

[私は Python 構文に切り替えます。私にとってはより簡単で、あなたが解釈できると確信しています。]

if var <= 3:
    if var == 2:
        # do something
    elif var == 3:
        # do something
    else: 
        raise Exception
else:
    if var == 4:
        # do something
    elif var == 5:
        # do something
    else:
        raise Exception

if ステートメントは、フラット リストではなくツリーを形成します。このリストに条件を追加すると、ツリーの中心を揺らします。n回の比較のフラット シーケンスでは、平均でn /2 ステップかかります。ツリーは、log( n ) の比較を行う一連の比較につながります。

于 2008-10-05T23:56:13.000 に答える
10

まあ、ほとんどの場合、たとえば数値順に並べられた値を持つことの読みやすさは、比較命令の数を減らすことによって得られる可能性のある小さな利点を無効にするだろうと私は信じています。

そうは言っても、すべての最適化と同様に:

  1. それを機能させる
  2. それを測定する
  3. 十分に速い場合は、そのままにしておきます
  4. 遅すぎる場合は、最適化してください

ああ、私はおそらく最初からスイッチ/ケースを使用するでしょう!;-)

于 2008-10-05T23:26:57.003 に答える
7

これが発生する典型的なケース(あなたの投稿のように文字通り5つのオプションがあります)は、defmpegのdecode_cabac_residual関数にありました。これはかなり重要でした。プロファイリング(非常に重要です。プロファイリングの前に最適化しないでください!)では、H.264ビデオのデコードに費やされた時間の10〜15%以上がカウントされたことが示されました。ifステートメントは、デコードされるさまざまなタイプの残差に対して異なる方法で計算された一連のステートメントを制御しました。残念ながら、関数が5つのタイプのそれぞれに対して5回複製された場合、コードサイズが原因で速度が大幅に低下しました。残差。したがって、代わりに、ifチェーンを使用する必要がありました。

プロファイリングは、可能性の観点からそれらを順序付けるために、多くの一般的なテストストリームで行われました。上が最も一般的で、下が最も少なかった。これにより、速度がわずかに向上しました。

さて、PHPでは、上記の例のように、Cで得られる低レベルのスタイル速度の向上ははるかに少ないと思います。

于 2008-10-05T23:26:01.610 に答える
2

switch/case ステートメントを使用することは、間違いなくここに行く方法です。

これにより、コンパイラ (インタプリタ) はジャンプ テーブルを利用して、N 回の比較を行うことなく正しい分岐に到達することができます。0、1、2、.. としてインデックス付けされたアドレスの配列を作成すると考えてください。そうすれば、1 回の操作で配列内の正しいアドレスを検索できます。

さらに、case ステートメントでは構文上のオーバーヘッドが少ないため、読みやすくなります。

更新:比較が switch ステートメントに適している場合、これはプロファイルに基づく最適化が役立つ領域です。現実的なテスト ロードで PGO ビルドを実行することにより、システムはブランチの使用情報を生成し、これを使用してパスを最適化できます。

于 2008-10-05T23:57:52.807 に答える
1

コードが追加のテストを実行する必要がある場合は、実行速度が確実に遅くなります。コードのこのセクションでパフォーマンスが重要な場合は、最も一般的なケースを最初に配置する必要があります。

パフォーマンスが十分に速いかどうかわからない場合は、通常、「測定してから最適化する」方法に同意しますが、コードをできるだけ速く実行する必要があり、修正がテストの再配置と同じくらい簡単である場合は、私は今コードを高速化し、ライブになってから測定を行って、仮定(たとえば、3が80%の確率で発生する)が実際に正しいことを確認します。

于 2008-10-05T23:36:39.013 に答える
1

呼び出すコードブロックの配列を試してみることができます。その場合、すべてのコードブロックのオーバーヘッドは同じになります。

Perl 6:

our @code_blocks = (
  { 'Code Block 0' },
  { 'Code Block 1' },
  { 'Code Block 2' },
  { 'Code Block 3' },
  { 'Code Block 4' },
  { 'Code Block 5' },
);

if( 0 <= $var < @code_blocks.length ){
  @code_blocks[$var]->();
}
于 2008-10-06T18:37:08.103 に答える
1

PHP の質問に答えるのではなく、もう少し一般的な質問に答えます。ある種の解釈が行われるため、PHP には直接適用されません。

多くのコンパイラは、必要に応じて if-elif-elif-... ブロックとの間で変換してブロックを切り替えることができ、elif 部分のテストは十分に単純です (残りのセマンティクスはたまたま互換性があります)。3 ~ 4 回のテストでは、ジャンプ テーブルを使用しても必ずしも何も得られるとは限りません。

その理由は、CPU の分岐予測子が何が起こるかを予測するのに非常に優れているからです。実際には、命令フェッチに対するプレッシャーが少し高くなるだけですが、世界を破壊することはまずありません。

ただし、あなたの例では、ほとんどのコンパイラは $var が定数 3 であることを認識し、if..elif.. ブロックで $var を 3 に置き換えます。これにより、式が定数になるため、true または false のいずれかに折り畳まれます。すべての false ブランチはデッドコード エリミネーターによって強制終了され、true のテストも削除されます。残っているのは、$var == 3 の場合です。ただし、PHP がそれほど賢いとは限りません。通常、$var の伝播はできませんが、一部の呼び出しサイトからは可能かもしれません。

于 2008-10-06T02:51:23.550 に答える
0

順序を最適化することによるパフォーマンスの違い、または実質的にバイナリ ツリーになるように再配置することによるパフォーマンスの違いが大きな違いを生むかどうかを判断できるのは、あなただけです。しかし、PHP でそれを考えるのに、1 秒間に数千回ではなく、数百万回の回数が必要になると思います (他の言語ではさらにそうです)。

時間を計る。上記の if/else if/else ステートメントを、アクションを実行せず、$var を選択肢の 1 つにせずに、1 秒間に何回実行できるかを確認してください。

于 2008-10-06T02:35:35.843 に答える
0

純粋に等値分析であるコードでは、パフォーマンスが向上するため、スイッチ/ケースに移動します。

$var = 3; // we'll say it's set to 3 for this example
switch($var)
 {
   case 4:
      //do something
      break;
   case 5:
      //do something
      break;
   case:
      //do something when none of the provided cases match (same as using an else{ after the elseif{
 }

より複雑な比較を行う場合は、それらをスイッチにネストするか、elseif を使用します。

于 2008-10-06T02:12:59.150 に答える
0

オブジェクト指向言語では、オプションが大規模な if を提供する場合、それ//do somethingは値を含むオブジェクトに動作 (ブロックなど) を移動するだけであることを意味します。

于 2008-10-06T02:16:58.970 に答える