0

我有一个框架,允许用户对特定数据源(足球经理 2010 游戏数据库,对于那些感兴趣的人)进行查询。

在这个框架中,我的框架可以运行两种不同的模式:实时模式和缓存模式。我希望使用这个框架的用户能够通过调用不同的构造函数(例如new Context(Mode.Cached))来进行切换。这应该是用户应该进行的唯一切换,因此他仍然可以进行所有相同的 Linq 调用,但是当他的应用程序更适合时才使用缓存模式。清除。

我决定使用 PostSharp 应该是我的最佳选择,因为:

  • 在每个属性上创建一个方面(已经被属性修饰过)
  • 在这方面,检查我们是否处于CachedRealtime模式
  • 从内存或缓存中返回值

那行得通。但!速度不够好。在 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 ms 是非常合理的。

但!在 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;
}

而且它需要782 毫秒,超过 10 倍!

我将方面创建为:

[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)),而是使用创建上下文的工厂方法。然后在两个不同的类中实现你的两种行为,它们共享抽象超类型所需的任何东西。使用方面和反射来解决没有简单直接解决方案的问题。


代替

[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 回答