如何才能真正快速地做到这一点?

发布于 2024-08-11 17:40:59 字数 1915 浏览 5 评论 0原文

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

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

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

  • 在每个属性上创建一个方面(已由属性装饰)
  • 在该方面,检查我们是否处于缓存或实时状态 模式
  • 从内存或缓存返回值,

这可行。但!速度不够好。对 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;
}

需要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; }

我怎样才能让它表现良好?!

I have a framework that allows users to do queries to a specific datasource (the Football Manager 2010 ingame database, for those of you interested).

In this framework, I have two different modes wherein my framework can run: realtime and cached mode. I want users who use this framework to be able to switch by just calling a different constructor (e.g. new Context(Mode.Cached)). That should be the only switch a user should make, so he can still have all the same Linq calls, but just use Cached mode when his application fits better. Clear.

I had decided that using PostSharp should be my best choice because:

  • Create an aspect on every property (that's already been decorated by an attribute)
  • In that aspect, check whether we are in Cached or Realtime mode
  • Return the value either from memory or from cache

Well that works. BUT! Speed is not good enough. When doing the following on 90.000 objects:

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

It takes only 63 ms. (ReadFromBuffer is a highly optimized function which takes byte[], int, Type and returns object), 63 ms is very reasonable considering the large amounts of objects.

But! In PostSharp, I implemented quite the same using this:

    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);
            }

Now I call this using

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

And it takes 782 ms, more than 10 times as much!

I created the aspect as:

[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
}

And the property is decorated like

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

How can I get this to perform well?!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青衫儰鉨ミ守葔 2024-08-18 17:40:59

使用 PostSharp 2.0 的 LocationInterceptionAspect 可以获得更好的结果。

但是你应该避免在运行时使用 eventArgs.Method.ReturnType ;而是获取方法 RuntimeInitialize 中的值并将其存储在字段中。所以运行时不使用System.Reflection。

You could get much better results using PostSharp 2.0's LocationInterceptionAspect.

But then you should avoid using eventArgs.Method.ReturnType at runtime; rather get the value in method RuntimeInitialize and store it in a field. So System.Reflection is not used at runtime.

浮生面具三千个 2024-08-18 17:40:59

不要使用 new Context(Mode.Cached)) 创建上下文,而是使用一个创建上下文的工厂方法。然后在两个不同的类中实现这两种行为,这两个类共享抽象超类型所需的任何内容。使用方面和反射来解决没有简单直接解决方案的问题。


替换

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

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

其中 PlayerAttrs 有一个运算符 Int16,可以根据需要将自身转换为 Int16,具有所需的偏移量,并执行适当的缓存/非缓存查找。

Instead of creating your context using new Context(Mode.Cached)), have a factory method which creates a context. Then implement your two behaviours in two different classes which share whatever they need of an abstract super type. Use aspects and reflection to solve problems which don't have a simple direct solution.


replace

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

with

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

where PlayerAttrs has an operator Int16 to convert itself to Int16 on demand,has the offset required, and performs the appropriate cached/non-cached lookup.

煮茶煮酒煮时光 2024-08-18 17:40:59
  1. 使用 CompileTimeValidate 方法检查它是否是一个属性
  1. Use CompileTimeValidate method to check if its a property or not
绅士风度i 2024-08-18 17:40:59

反思可能代价高昂。您可能尝试的一件事是在运行时实际编译此类的包装器,并节省当前的每次调用命中率。

Reflection can be expensive. One thing you might try is actually compiling a wrapper for this class at runtime, and saving yourself the per-call hit that you currently have.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文