优化多分派通知算法在C#中? [英] Optimizing multiple dispatch notification algorithm in C#?

查看:185
本文介绍了优化多分派通知算法在C#中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

抱歉标题,我想不出更好的方式来说明问题。基本上,我想实现一个碰撞系统在游戏中。我希望能够注册一个冲突处理处理两个对象(在任一给定顺序),可转换为特定类型的任何冲突。因此,如果播放器:船舶:实体激光:粒子:实体,和处理程序(船舶,颗粒)(激光,实体)注册比为(激光,球员碰撞),这两个处理程序应通知,以正确的顺序参数,以及碰撞(激光,激光)应通知第二只处理程序。

Sorry about the title, I couldn't think of a better way to describe the problem. Basically, I'm trying to implement a collision system in a game. I want to be able to register a "collision handler" that handles any collision of two objects (given in either order) that can be cast to particular types. So if Player : Ship : Entity and Laser : Particle : Entity, and handlers for (Ship, Particle) and (Laser, Entity) are registered than for a collision of (Laser, Player), both handlers should be notified, with the arguments in the correct order, and a collision of (Laser, Laser) should notify only the second handler.

一个code段胜过千言万语,所以这里就是我现在做(naieve法):

A code snippet says a thousand words, so here's what I'm doing right now (naieve method):

    public IObservable<Collision<T1, T2>> onCollisionsOf<T1, T2>()
        where T1 : Entity
        where T2 : Entity
    {
        Type t1 = typeof(T1);
        Type t2 = typeof(T2);
        Subject<Collision<T1, T2>> obs = new Subject<Collision<T1, T2>>();
        _onCollisionInternal += delegate(Entity obj1, Entity obj2)
        {
            if (t1.IsAssignableFrom(obj1.GetType()) && t2.IsAssignableFrom(obj2.GetType()))
                obs.OnNext(new Collision<T1, T2>((T1) obj1, (T2) obj2));
            else if (t1.IsAssignableFrom(obj2.GetType()) && t2.IsAssignableFrom(obj1.GetType()))
                obs.OnNext(new Collision<T1, T2>((T1) obj2, (T2) obj1));
        };
        return obs;
    }

不过,这种方法是相当缓慢的(可衡量的,我失去了〜2 FPS实现这个之后),所以我在寻找一种方式来剃一对夫妇次/分配关闭此

However, this method is quite slow (measurable; I lost ~2 FPS after implementing this), so I'm looking for a way to shave a couple cycles/allocation off this.

我想过(如,花了一个小时实施再抨击我的头靠在墙上的是这样一个白痴),一个是把类型的顺序基于其散列code的方法,然后把它们放到一个词典,每个条目是处理程序用于对这种类型的用布尔指示处理程序是否想要的参数顺序颠倒的链表。不幸的是,这并不对派生类型工作,因为如果派生类型是通过在,也不会通知订户为的基本类型。任何人都可以想办法不是检查每一种类型对(两次的),看它是否匹配?

I thought about (as in, spent an hour implementing then slammed my head against a wall for being such an idiot) a method that put the types in an order based on their hash code, then put them into a dictionary, with each entry being a linked list of handlers for pairs of that type with a boolean indication whether the handler wanted the order of arguments reversed. Unfortunately, this doesn't work for derived types, since if a derived type is passed in, it won't notify a subscriber for the base type. Can anyone think of a way better than checking every type pair (twice) to see if it matches?

谢谢, 罗伯特·

推荐答案

所有的反射是不会要快。请注意反射发生的每一次碰撞上。这就是问题所在。

All that reflection is not going to be fast. Notice how the reflection happens on every collision. That's the problem.

若干思考。

思想头号:访问者模式

在面向对象的语言来实现相当快的双虚拟调度的标准方式是通过建设访问者模式的实现。

The standard way to implement reasonably fast double-virtual dispatch in OO languages is via building an implementation of the visitor pattern.

您可以实现一个访问者模式,即在vistior每个受维护的事情做在这种情况下,列表?然后你的加法器的方法包括寻找合适的地方写新的事情,然后委托添加到东西。当碰撞发生,你开始访客做双调度,找到事情做的委托,并调用它。

Can you implement a visitor pattern whereby each acceptor in the vistior maintains a list of "things to do in this situation"? Then your adder method consists of identifying the right place to write the new "thing to do", and then add the delegate to that thing. When the collision happens, you start the visitor to do double dispatch, find the delegate of things to do, and invoke it.

您是否需要增加一倍以上,派遣过?高效的多重虚拟调度是可行的,但它不是完全明了。

Do you need more than double-dispatch ever? Efficient multiple-virtual dispatch is doable but it's not exactly straightforward.

思想之二:动态调度

C#4的动态分配。它的工作方式是我们用来反射在第一时间调用点遇到来分析调用点。然后,我们产生全新的IL动态地执行调用,并缓存IL。在第二个电话,我们反思的观点,看看他们是否有完全相同的类型和以前一样。如果是这样,我们重新使用现有的IL并调用它。如果不是这样,我们再次做了分析。如果参数通常只有几类,然后缓存很快开始暂时只安打,没有失误,并表现还算是不错的考虑了所有的事情。肯定比很多反映的每一个时间快。我们做的每一次唯一的反映是参数的运行时类型的分析。

C# 4 has dynamic dispatch. The way it works is we use reflection the first time the call site is encountered to analyze the call site. We then generate fresh new IL dynamically to execute the call, and cache the IL. On the second call, we reflect upon the arguments to see whether they are the exact same types as before. If they are, we re-use the existing IL and just call it. If not, we do the analysis again. If the arguments are typically of only a few types then the cache very quickly starts being only hits and no misses, and performance is actually quite good all things considered. Certainly faster than lots of reflection every single time. The only reflection we do every time is the analysis of the runtime type of the arguments.

思想之三:实现自己的动态分派

Thought number three: implement your own dynamic dispatch

有什么魔力什么DLR在做什么。它做了一些分析一次,吐出一些IL和缓存结果。我怀疑你的痛苦正在发生的事情,因为你每次都重新做了分析。

There's nothing magical about what the DLR is doing. It does some analysis once, spits some IL and caches the result. I suspect your pain is happening because you're re-doing the analysis every time.

这篇关于优化多分派通知算法在C#中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆