0

次のようなプリミティブデータ型を含む計算を実行するC#コードがあります。

public sealed class Calculation
{
    private readonly int a, b, c;

    public Calculation(int _a, int _b, int _c)
    {
        this.a = _a; this.b = _b; this.c = _c;
    }

    public int DoCalculation(int rfactor, int lfactor)
    {
        return (a / rfactor) + (b / lfactor) + ((a/b)*(rfactor+lfactor));
    }
}

{a、b、c}がコンパイル時定数である場合、DoCalculation(...)メソッドの式はCILレベルで大幅に最適化できます。「読み取り専用」のヒントが与えられた場合、JITerがコンパイル時定数の最適化と同様にDoCalculation(...)メソッドを最適化するかどうか疑問に思っています。

4

2 に答える 2

4

いいえ、変数は定数ではないためです。それらの値は、ジッティングの時点ではわかりません。読み取り専用であっても、ランタイム値が不明であり、インスタンス間で異なる可能性があるという事実は変わりません。

于 2012-07-13T21:09:26.887 に答える
4

あなたの例は素晴らしいものではありませんが、そうです、この種の最適化は確かに起こります。複数のレベルで、C# コンパイラーが最初に狙いを定めます。単純な式をリテラル値で評価し、それらを結果に置き換えます。また、コンパイル時にオーバーフローを検出できる方法。

ジッターオプティマイザーもこれを行いますが、これは通常、メソッドのインライン化の結果として行われます。しかし、それはあなたの DoCalculation() メソッドでは起こりません。複雑すぎてインライン化できません。しかし、次のような些細なことです:

    public static int DoCalculation(int a, int b) {
        return a * b;
    }

確かにインライン化され、最適化されます。Console.WriteLine(Calculation.DoCalculation(4, 5)) と同様に、以下が生成されます。

00000003  call        5927D408 
00000008  mov         ecx,eax 
0000000a  mov         edx,14h                      // <=== here
0000000f  mov         eax,dword ptr [ecx] 
00000011  mov         eax,dword ptr [eax+38h] 
00000014  call        dword ptr [eax+14h] 

結果 4 * 5 = 20 = 0x14 がどのように事前計算されたかに注意してください。

オプティマイザーがあきらめる前に、メソッドがインライン化できる正確なタイミングと、式がどの程度関与するかについての厳密な規則はありません。これは変更される可能性があり、ジッターの種類 (x86、x64、ARM) によって異なります。

このコードがクリティカル パスの奥深くに存在し、プロファイラーが実行時間の 80% 以上を占めていると言った場合 (プロファイラーをスキップしないでください!)、時間をかけてメソッドをいじって確認する価値があります。あなたが得るもの。リリース モードのビルドをデバッグし、オプティマイザーを実行できるようにしてください。[ツール] + [オプション]、[デバッグ]、[全般] で、[モジュールの読み込み時に JIT 最適化を抑制する] オプションのチェックを外します。

小さな変更が大きな影響を与える可能性があり、一見些細な編集でコードの速度が 2 倍になると、かなり気分が良くなります。そうでなくても、一日の試行錯誤の後、どこにも行き着くことができません。保証はありません。しかし、どのような種類のコードが適切に動作するかについての「感覚」、つまり非常に価値のある経験と洞察を確実に身につけることができます。

于 2012-07-13T21:20:04.563 に答える