10

例: 1 から 7 までの数字を曜日にマップしています。7 項目の case ステートメントで検索するか、7 項目の定数配列を使用できます。どちらが速いですか?

ケース例:

function GetDayNameBr(Num: Integer): String;
begin
  case Num of
    1: Result := 'Domingo';
    2: Result := 'Segunda';
    3: Result := 'Terça';
    4: Result := 'Quarta';
    5: Result := 'Quinta';
    6: Result := 'Sexta';
    7: Result := 'Sábado';
  end;       
end;

定数配列の例:

function GetDayNameBr(Num: Integer): String;
const
  DayNames: array [1..7] of String = (
    'Domingo',
    'Segunda',
    'Terça',
    'Quarta',
    'Quinta',
    'Sexta',
    'Sábado');
begin
  Result := DayNames[Num];       
end; 
4

3 に答える 3

11

これら 2 つの関数のパフォーマンス特性が異なる主な理由は、これらの機能が異なるためです。あなたは同じように比較していません。入力値が 1 から 7 までの範囲にある場合、動作は同じです。ただし、入力値がその範囲外の場合、動作は発散します。

を使用する最初のバージョンは、case最初に値が 1 から 7 の範囲内にあることを確認する必要があります。その後、実際に に割り当てることが許可されResultます。値が 1 から 7 の範囲にある場合、コンパイラは case ステートメントjmpを次のような無条件ステートメントに変換します。

jmp dword ptr [eax*4+$40428f]

eax日指数はこちら。そして、これらのジャンプのターゲットは、単に文字列リテラルをResult変数に代入する命令です。

配列を使用する 2 番目のバージョンは、入力値が範囲内にあるかどうかをチェックしません。入力値が範囲外であっても、配列に直接インデックスを付けます。もちろん、そのような配列インデックスは未定義の動作につながります。したがって、これは動作が分岐する場所です。

これを純粋にパフォーマンスから見て、関数のセマンティックの違いを無視すると、主な違いは、使用するバージョンcaseには配列バージョンには存在しない入力値のテストと分岐があることです。さらに、使用しているバージョンcaseはコードが大きいため、おそらくキャッシュ フレンドリーではありません。そのため、コードの分析から、配列バージョンの方が高速であると予想できます。行うことが少なく、分岐せず、コードが小さくなります。

パフォーマンスが実際に重要な場合は、このコードが実行される実際の設定で現実的なタイミングを実行する必要があります。それらは人工的であるため、私はそれらのタイミングを実行できません。いつでも、コードのコンテキストでのみ真の意味を持ちます。プログラムの設定では、2 つのバージョンの違いを測定できない可能性が非常に高いです。その場合、上記の分析は意味がありません。

于 2013-06-26T15:38:58.760 に答える
9

どちらも、少なくとも x86 では、つまり 32 ビット Delphi コンパイラでは、ほぼ同等に高速です。

32 ビットを対象とする場合、配列はインデックス付きルックアップを生成しますが、ケースはルックアップ テーブルに基づいてジャンプ命令を生成します。Array は少し速くなりますが、ほんのわずかです。

しかし、私は、64ビットをターゲットにしている場合、case命令がx64の下でそのようなルックアップテーブルを生成しないことを発見しました。比較と条件付きジャンプ ( のようなもの) のリストを生成しますが、これは著しく遅くなります。if value=1 then ... else if value=2 then...

あなたの場合、単純な整数値の代わりに配列ルックアップと列挙を使用します。整数としてコンパイルされますが、デバッグと進化がはるかに簡単になります。列挙が変更された場合、定数配列はそれ以上コンパイルされないため、実行時ではなくコンパイル時に何らかの問題を回避できます。このような小さなリストには、整数ではなく列挙を徹底的に使用するようにしています。これは、Delphi/pascal のストレートの 1 つであり、C# や Java では非常に恋しいです。

type
  TDay = (dDomingo, dSegunda, dTerca, dQuarta, dSexta, dSabado);

function GetDayNameBr(Num: TDay): String; 
const
  DayNames: array [TDay] of String = (
    'Domingo',
    'Segunda',
    'Terça',
    'Quarta',
    'Quinta',
    'Sexta',
    'Sábado');
begin
  Result := DayNames[Num];       
end; 

または、さらに良い私見ではDayNames[Num]、すべてのプラットフォームで最も安全で最速のコードに直接記述します。

于 2013-06-26T18:14:38.013 に答える
8

どちらも超高速ですが、違いがあったとしても、アレイ アプローチの方が目立たないほど高速だと思います。

ただし、ロジックを生データから分離するという理由だけで、配列アプローチを使用することは間違いありません。(2 つの異なる言語をサポートする必要があると想像してください。それぞれの場合にどのようにサポートするかを比較してください。) また、より慣用的です。

于 2013-06-26T14:08:12.620 に答える