2012-04-27 5 views
4

可能性の重複:
Difference between declaring variables before or in loop?C#何が速いですか、関数の先頭にループ変数を宣言しますか?

私はいつも疑問に思って、それは次のように行うには速いです:

int i; 

for (i=0;i<...) 
for (i=0;i<...) 
for (i=0;i<...) 
for (i=0;i<...) 

または

for (int i=0;i<...) 
for (int i=0;i<...) 
for (int i=0;i<...) 
for (int i=0;i<...) 

意味、私は複数のループを1つの関数で持っている場合、ループ反復変数を宣言して複数回使用するか、ループごとに宣言すればより速く動作しますか?

+10

"これは速いです"という問題ではなく、変数の範囲を必要最小限に抑えることです。プログラマとして、そのような「最適化」よりも重要な考慮事項があります。 – spender

+0

テストしましたか?このような小さなものを最適化する前に常に測定してください。私はあなたがループの中でやっていることは、私よりも最適化することができることを賭ける –

+0

それをテストしましたか? –

答えて

4

生成されるILは、(リリースビルド用に)両方のアプローチでほぼ同じです。

test1():      test2() 
{        { 
    .maxstack 2      .maxstack 2 
    .locals init (     .locals init (
     [0] int32 result,    [0] int32 result, 
     [1] int32 i)     [1] int32 i, 
             [2] int32 V_2) 
    L_0000: ldc.i4.0    L_0000: ldc.i4.0 
    L_0001: stloc.0     L_0001: stloc.0 
    L_0002: ldc.i4.0    L_0002: ldc.i4.0 
    L_0003: stloc.1     L_0003: stloc.1 
    L_0004: br.s L_000e    L_0004: br.s L_000e 
    L_0006: ldloc.0     L_0006: ldloc.0 
    L_0007: ldc.i4.1    L_0007: ldc.i4.1 
    L_0008: add      L_0008: add 
    L_0009: stloc.0     L_0009: stloc.0 
    L_000a: ldloc.1     L_000a: ldloc.1 
    L_000b: ldc.i4.1    L_000b: ldc.i4.1 
    L_000c: add      L_000c: add 
    L_000d: stloc.1     L_000d: stloc.1 
    L_000e: ldloc.1     L_000e: ldloc.1 
    L_000f: ldc.i4.s 10    L_000f: ldc.i4.s 10 
    L_0011: blt.s L_0006   L_0011: blt.s L_0006 
    L_0013: ldc.i4.0    L_0013: ldc.i4.0 
    L_0014: stloc.1     L_0014: stloc.2 
    L_0015: br.s L_001f    L_0015: br.s L_001f 
    L_0017: ldloc.0     L_0017: ldloc.0 
    L_0018: ldc.i4.1    L_0018: ldc.i4.1 
    L_0019: add      L_0019: add 
    L_001a: stloc.0     L_001a: stloc.0 
    L_001b: ldloc.1     L_001b: ldloc.2 
    L_001c: ldc.i4.1    L_001c: ldc.i4.1 
    L_001d: add      L_001d: add 
    L_001e: stloc.1     L_001e: stloc.2 
    L_001f: ldloc.1     L_001f: ldloc.2 
    L_0020: ldc.i4.s 10    L_0020: ldc.i4.s 10 
    L_0022: blt.s L_0017   L_0022: blt.s L_0017 
    L_0024: ldloc.0     L_0024: ldloc.0 
    L_0025: ret      L_0025: ret 
}        } 

これは、それはかなり明確になります:

static int test1() 
{ 
    int result = 0; 
    int i; 

    for (i = 0; i < 10; ++i) 
     ++result; 

    for (i = 0; i < 10; ++i) 
     ++result; 

    return result; 
} 

static int test2() 
{ 
    int result = 0; 

    for (int i = 0; i < 10; ++i) 
     ++result; 

    for (int i = 0; i < 10; ++i) 
     ++result; 

    return result; 
} 

これは私が簡単に比較のために並べて配置したリリースビルドのために、次のILを生成します。

は、このコードを考えてみましょう'i'がループのローカルであるバージョンを選択することをお勧めします。これはより良い方法です。

しかし、ループの外側で宣言されたループカウンタを持つバージョンは、intを0に初期化するのに必要な時間だけ、かなり高速になります。

+0

ありがとう! 8moretogo – Istrebitel

+0

すばらしい答え。それだけではなく、ILとの証拠/説明です。 +1。 –

+2

ILは、「どちらが速いの?」という質問とは何が関係していますか? ILは実行するものではありません! –

3

理論的には、メモリの場所が1つしかなく、再利用されるため、前者は高速にする必要があります。

+0

該当しません。 ILは両方のアプローチでほぼ同じです。 –

+0

まあ、そうではありません - 私はdotPeekを使って両方のバージョンを解体しましたが、それらは異なっていました。同じものになる唯一の方法は、コンパイラの最適化がある場合ですが、この場合は何が起こったのかは異なります。 –

+0

以下に掲載したILコードをご覧ください。 2つのアプローチの間ではほとんど同じです。ループにローカルに 'i'を宣言するための唯一のオーバーヘッドは、関数の先頭にある単一の.initです。あなたはおそらくデバッグビルドを見ていましたか? –

1

ここでスピードの問題はありませんが、ここでは変数が必要なスコープと関連があります。ループ内でのみ使用できるようにする必要がある場合は、ループの外側にないループで宣言してください。しかし、すべてのループで利用できるようにする必要がある場合、最初のアプローチは高速です。

+0

Brr ... forsの外で変数を宣言する方が速いですか?そうではありませんか? – Istrebitel

+0

上記の例では、はい! – ranjez

0

2つのコードは同じJITtedコードを生成します。だから、実際にはパフォーマンスの向上はありません。

関連する問題