0

int i = 3;

このコードの間にパフォーマンスの違いはありますか?

if(i == 2)
   DoA();
if(i == 3)
   DoB();
if(i == 4)
   DoC();

そしてこのコード:

if(i == 2)
   DoA();
else if(i == 3)
   DoB();
else if(i == 4)
   DoC();

オプションのELSEを使用すると、CPUがコードを理解する方法に影響するかどうか疑問に思います。2番目のアプローチを使用する場合、CPUi2他の2つの条件をチェックしませんが、最初のアプローチでは最初の条件はtrue(i == 2)ですが、CPUは2番目と3番目の条件をチェックします。これは本当ですか?

4

5 に答える 5

3

パフォーマンスに基づいてこれを決定するべきではありません。コードの2つのバージョンは、異なる意味を持っています。正しいものを使用する必要があります。

例えば:

if (s == null)
{
    // do something
    s = GetNewValue();
}
if (s == "")
{
    // do something else
}

がない場合else、このコードは次のことを意味します。

  • の場合、最初のブロックを実行しsますnull
  • 次に、そのブロックがに変更さsれた""(または最初から)場合s""、2番目のブロックを実行します。

else2番目の前に余分なifものがある場合、コードは次のことを意味します。

  • の場合、最初のブロックを実行しsますnull
  • 最初からでsはなく、に等しい場合は 2番目のブロックを実行します。null""

比較対象の変数がブロックによって変更されないために違いがない場合は、コードの意味が明示的になるため、を使用してください。else

于 2012-12-02T09:18:30.673 に答える
2

もちろん、それは影響します-より良いために!これらを使用することにより、コンパイラは他のif-checkをスキップしてパフォーマンスを向上させるため、これは不必要とはまったく逆です。

ただし、心配する必要はありません。例のパフォーマンスの違いはごくわずかであり、重要ではありません。

于 2012-12-02T08:58:03.490 に答える
1

2つのステートメントのILコードは次のとおりです。

.method private hidebysig static void m1() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.2 
    L_0005: ceq 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_0014
    L_000e: call void ConsoleApplication1.Program::DoA()
    L_0013: nop 
    L_0014: ldloc.0 
    L_0015: ldc.i4.3 
    L_0016: ceq 
    L_0018: ldc.i4.0 
    L_0019: ceq 
    L_001b: stloc.1 
    L_001c: ldloc.1 
    L_001d: brtrue.s L_0025
    L_001f: call void ConsoleApplication1.Program::DoB()
    L_0024: nop 
    L_0025: ldloc.0 
    L_0026: ldc.i4.4 
    L_0027: ceq 
    L_0029: ldc.i4.0 
    L_002a: ceq 
    L_002c: stloc.1 
    L_002d: ldloc.1 
    L_002e: brtrue.s L_0036
    L_0030: call void ConsoleApplication1.Program::DoC()
    L_0035: nop 
    L_0036: ret 
}

.method private hidebysig static void m2() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.2 
    L_0005: ceq 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_0016
    L_000e: call void ConsoleApplication1.Program::DoA()
    L_0013: nop 
    L_0014: br.s L_003a
    L_0016: ldloc.0 
    L_0017: ldc.i4.3 
    L_0018: ceq 
    L_001a: ldc.i4.0 
    L_001b: ceq 
    L_001d: stloc.1 
    L_001e: ldloc.1 
    L_001f: brtrue.s L_0029
    L_0021: call void ConsoleApplication1.Program::DoB()
    L_0026: nop 
    L_0027: br.s L_003a
    L_0029: ldloc.0 
    L_002a: ldc.i4.4 
    L_002b: ceq 
    L_002d: ldc.i4.0 
    L_002e: ceq 
    L_0030: stloc.1 
    L_0031: ldloc.1 
    L_0032: brtrue.s L_003a
    L_0034: call void ConsoleApplication1.Program::DoC()
    L_0039: nop 
    L_003a: ret 
}

生成されたILは同じではないようです。

編集1

方法でm2()

L_0014: br.s L_003a
.
.
.
L_0027: br.s L_003a

その場合、メソッド'm2()'の方が高速です。

于 2012-12-02T09:05:05.530 に答える
0

はい、次のコードを検討する場合は、elseを使用してください。

if(predicateA){
  //do Stuff
}
if(predicateB){
  // do more stuff
}

また

if(predicateA){
  //do stuff 
}
else if(predicateB){
  //do stuff
}

2番目のケースでは、predicateAがtrueの場合、predicateB(およびそれ以降の述語)を評価する必要はありません(したがって、コード全体がより高速に実行されます)。一方、最初の例では、predicateAがtrueの場合、predicateBは常に評価されます。また、predicateAとpredicateBが相互に排他的でない場合は、予期しない驚きが生じる可能性があります。

于 2012-12-02T09:01:49.937 に答える
0

'DoX'が'a=b'のようなステートメントである場合; その場合、最初の実行がより高速になる可能性がありますが、コンパイラが相互に排他的な比較に最適なオプションを見つけられない可能性もあります。

一部のアーキテクチャでは、これら3つの比較は次のように変換できます。

 cmp a,2;
 movlt  b, c;
 moveq  c, d;
 movgt  e, f;

これらが非常に単純なステートメントであり、プログラマーが少し助けてくれる場合。

パフォーマンスを向上させるために問題を変換する他の実用的な方法は、関数ポインターを使用し、範囲外の配列にアクセスする可能性がないことを保証するためにすべてのステップを実行することです。

 void (*do)()[]={ doA, doB, doC };

 do[i]();  
 // mov eax, do[eax*4];
 // call [eax]
于 2012-12-02T10:32:31.153 に答える