0

私は、ユーザーが特定のデータソース (興味のある方のために、Football Manager 2010 のゲーム内データベース) に対してクエリを実行できるようにするフレームワークを用意しています。

このフレームワークには、フレームワークを実行できる 2 つの異なるモード (リアルタイム モードとキャッシュ モード) があります。このフレームワークを使用しているユーザーが、別のコンストラクターを呼び出すだけで切り替えられるようにしてほしい (例: new Context(Mode.Cached))。これは、ユーザーが行う必要がある唯一の切り替えである必要があるため、ユーザーは引き続きすべて同じ Linq 呼び出しを行うことができますが、アプリケーションがより適している場合はキャッシュ モードを使用するだけです。クリア。

次の理由から、PostSharp を使用することが最善の選択であると判断しました。

  • すべてのプロパティにアスペクトを作成します (属性によって既に装飾されています)。
  • その面では、私たちがモードにいるCachedかどうかを確認してくださいRealtime
  • メモリまたはキャッシュから値を返す

それはうまくいきます。しかし!速度が十分ではありません。90.000 個のオブジェクトに対して次の操作を行う場合:

foreach (Player p in fm.Players)
{
    int ca = (short)ProcessManager.ReadFromBuffer(p.OriginalBytes, PlayerOffsets.Ca, typeof(Int16));
}

わずか 63 ミリ秒かかります。(ReadFromBuffer は高度に最適化された関数で、 を受け取ってbyte[], int, Type返しますobject)、大量のオブジェクトを考慮すると、63 ミリ秒は非常に妥当です。

しかし!PostSharp では、これを使用してまったく同じものを実装しました。

    public override void OnInvocation(MethodInvocationEventArgs eventArgs)
    {
        if (eventArgs.Method.Name.StartsWith("~get_"))
        {
            if (Global.DatabaseMode == DatabaseModeEnum.Cached)
            {
                byte[] buffer = ((BaseObject)eventArgs.Instance).OriginalBytes;

                eventArgs.ReturnValue =
                        ProcessManager.ReadFromBuffer(buffer, this.Offset, eventArgs.Method.ReturnType);
            }

今、私はこれを使用して呼び出します

foreach (Player p in fm.Players)
{
    int ca = p.CA;
}

そして、10 倍以上の782 msかかります。

アスペクトを次のように作成しました。

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, PersistMetaData = true)]
internal class FMEntityAttribute : OnMethodInvocationAspect
{
    public FMEntityAttribute(int offset, int additionalStringOffset)
    {
        this.Offset = offset;
        this.AdditionalStringOffset = additionalStringOffset;
    }
    //blah blah AOP code
}

そして、プロパティは次のように装飾されています

    [FMEntityAttribute(PlayerOffsets.Ca)]
    public Int16 CA { get; set; }

どうすればこれをうまく機能させることができますか?!

4

4 に答える 4

2

PostSharp 2.0のLocationInterceptionAspectを使用すると、はるかに良い結果を得ることができます。

ただし、実行時にeventArgs.Method.ReturnTypeを使用することは避けてください。むしろ、RuntimeInitializeメソッドで値を取得し、それをフィールドに格納します。したがって、System.Reflectionは実行時に使用されません。

于 2009-11-18T07:40:59.173 に答える
1
  1. CompileTimeValidateメソッドを使用して、そのプロパティかどうかを確認します
于 2009-11-17T23:14:25.230 に答える
1

を使用してコンテキストを作成する代わりに、コンテキストを作成 new Context(Mode.Cached))するファクトリメソッドを用意します。次に、抽象スーパータイプに必要なものをすべて共有する2つの異なるクラスで2つの動作を実装します。アスペクトとリフレクションを使用して、単純な直接的な解決策がない問題を解決します。


交換

[FMEntityAttribute(PlayerOffsets.Ca)] public Int16 CA { get; }

public Int16 CA { get { return PlayerAttrs.Ca.Get(this); } }

ここでPlayerAttrs、必要に応じて自分自身をInt16に変換する演算子Int16があり、必要なオフセットがあり、適切なキャッシュ/非キャッシュルックアップを実行します。

于 2009-11-17T23:27:18.227 に答える
0

リフレクションにはコストがかかる場合があります。実行時にこのクラスのラッパーを実際にコンパイルし、現在の呼び出しごとのヒットを保存することをお試しください。

于 2009-11-18T02:28:32.427 に答える