11

double を構造体にラップすることで、私が測定単位系と呼ぶものを取得しようとしています。私は Meter、Second、Degree などの C# 構造を持っています。私の最初のアイデアは、コンパイラがすべてをインライン化した後、double を使用した場合と同じパフォーマンスが得られるというものでした。

私の明示的および暗黙的な演算子はシンプルで単純であり、コンパイラは実際にそれらをインライン化しますが、Meter と Second を使用したコードは double を使用した同じコードよりも 10 倍遅くなります。

私の質問は次のとおりです。とにかくすべてをインライン化する場合、C# コンパイラが Second を使用するコードを double を使用するコードと同じくらい最適化できないのはなぜですか?

2 番目は次のように定義されます。

struct Second
{
    double _value; // no more fields.

    public static Second operator + (Second left, Second right) 
    { 
        return left._value + right._value; 
    }
    public static implicit Second operator (double value) 
    { 
        // This seems to be faster than having constructor :)
        return new Second { _value = value };
    }

    // plenty of similar operators
}

アップデート:

構造体がここに収まるかどうかは尋ねませんでした。します。

コードがインライン化されるかどうかは尋ねませんでした。JIT はそれをインライン化します。

実行時に出力されるアセンブリ操作を確認しました。次のようなコードでは異なります。

var x = new double();
for (var i = 0; i < 1000000; i++)
{ 
    x = x + 2;
    // Many other simple operator calls here
}

そしてこのように:

var x = new Second();
for (var i = 0; i < 1000000; i++)
{ 
    x = x + 2;
    // Many other simple operator calls here
}

逆アセンブルには call 命令がなかったので、操作は実際にはインライン化されていました。それでも、違いは重要です。パフォーマンス テストでは、Second を使用すると、double を使用するよりも 10 倍遅くなることが示されています。

私の質問は (注意!): JIT で生成された IA64 コードが上記のケースと異なるのはなぜですか? 構造体を倍速で実行するにはどうすればよいですか? double と Second の間に理論的な違いはないようですが、私が見た違いの深い理由は何ですか?

4

2 に答える 2

4

これは私の意見です。同意しない場合は、黙って反対票を投じるのではなく、コメントを書いてください。

C#コンパイラはそれをインライン化しません。JITコンパイラはそうかもしれませんが、JITerの動作は単純ではないため、これは私たちにとって不確定です。

double演算子が実際に呼び出されない場合。オペランドは、オペコードを使用してスタックに追加されますadd。あなたの場合、メソッドop_Addが呼び出され、さらにstructスタックとの間で3つのコピーが行われます。

最適化するには、から始めstructますclass。少なくともコピーの量を最小限に抑えます。

于 2010-11-10T14:11:51.403 に答える
1

C# コンパイラは何もインライン化しません。JITはそれを行うかもしれませんが、そうする義務はありません。それでもかなり速いはずです。ただし、暗黙の変換を削除する可能性が+あります(以下のコンストラクターの使用法を参照)-もう1つの演算子を確認します。

private readonly double _value;
public double Value { get { return _value; } }
public Second(double value) { this._value = value; }
public static Second operator +(Second left, Second right) {
    return new Second(left._value + right._value);
}
public static implicit operator Second(double value)  {
    return new Second(value);
}

JIT インライン化は、特定のシナリオに限定されています。このコードは彼らを満足させますか? わかりにくいですが、ほとんどのシナリオで十分な速さで動作するはずです。問題は、double を追加するための IL オペコードがあることです。コードはいくつかの静的メソッドとコンストラクターを呼び出しているため、ほとんど機能しません。インライン化されている場合でも、常にオーバーヘッドが発生します。+

于 2010-11-10T14:07:30.670 に答える