XNA/C#:实体工厂和 typeof(T) 性能

发布于 2024-11-26 01:49:32 字数 1959 浏览 0 评论 0原文

在我们的游戏(针对移动设备)中,我们有几种不同的实体类型,我正在编写一个工厂/存储库来处理新实体的实例化。每个具体实体类型都有自己的工厂实现,这些工厂由 EntityRepository 管理。

我想这样实现存储库:

Repository
{
 private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;

 public T CreateEntity<T> (params) where T : IEntity
 {
      return factoryDict[typeof(T)].CreateEntity() as T;
 }
}

使用示例

var enemy = repo.CreateEntity<Enemy>();

,但我担心性能,特别是与上面的 typeof(T) 操作相关的性能。据我了解,编译器无法确定 T 的类型,必须在运行时通过反射确定,这是正确的吗?一种替代方法是:

Repository
{
 private Dictionary <System.Type, IEntityFactory> factoryDict;

 public IEntity CreateEntity (System.Type type, params)
 {
      return factoryDict[type].CreateEntity();
 }
}

在这种情况下,每当调用 typeof() 时都会使用它

var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);

,类型是现成的并且可以由编译器确定(对吗?)并且性能应该更好。会有显着差异吗?还有其他考虑吗?我知道我也可以在存储库中使用诸如 CreateEnemy 之类的方法(我们只有几种实体类型),这会更快,但我更愿意使存储库尽可能保持实体不感知。

编辑:

我知道这很可能不是瓶颈,我担心的是,当有稍微少一点糖分的替代品可用时,花时间去思考是一种浪费。我认为这是一个有趣的问题:)

我做了一些基准测试,结果证明非常有趣(并且似乎证实了我最初的怀疑)。

使用我在以下位置找到的性能测量工具 http://blogs.msdn.com/b/vancem /archive/2006/09/21/765648.aspx (它多次运行测试方法并显示平均时间等指标)我进行了一个基本测试,测试:

private static T GenFunc<T>() where T : class 
    {

        return dict[typeof(T)] as T;
    }

分别

    private static Object ParamFunc(System.Type type)
    {
        var d = dict[type];
        return d;
    }

称为

str = GenFunc<string>();

vs

str = (String)ParamFunc(typeof(String));

。 Paramfunc 在性能方面表现出显着的改进(平均执行时间是 GenFunc 的 60-70%),但测试相当初级,我可能会遗漏一些东西。具体来说,如何在通用函数中执行转换。

有趣的是,与每次都使用 typeof() 相比,通过“缓存”变量中的类型并将其传递给 ParamFunc 获得的性能很少(可以忽略不计)。

In our game (targeted at mobile) we have a few different entity types and I'm writing a factory/repository to handle instantiation of new entities. Each concrete entity type has its own factory implementation and these factories are managed by an EntityRepository.

I'd like to implement the repository as such:

Repository
{
 private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;

 public T CreateEntity<T> (params) where T : IEntity
 {
      return factoryDict[typeof(T)].CreateEntity() as T;
 }
}

usage example

var enemy = repo.CreateEntity<Enemy>();

but I am concerned about performance, specifically related to the typeof(T) operation in the above. It is my understanding that the compiler would not be able to determine T's type and it will have to be determined at runtime via reflection, is this correct? One alternative is:

Repository
{
 private Dictionary <System.Type, IEntityFactory> factoryDict;

 public IEntity CreateEntity (System.Type type, params)
 {
      return factoryDict[type].CreateEntity();
 }
}

which will be used as

var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);

in this case whenever typeof() is called, the type is on hand and can be determined by the compiler (right?) and performance should be better. Will there be a noteable difference? any other considerations? I know I can also just have a method such as CreateEnemy in the repository (we only have a few entity types) which would be faster but I would prefer to keep the repository as entity-unaware as possible.

EDIT:

I know that this may most likely not be a bottleneck, my concern is just that it is such a waste to use up time on reflecting when there is a slightly less sugared alternative available. And I think it's an interesting question :)

I did some benchmarking which proved quite interesting (and which seem to confirm my initial suspicions).

Using the performance measurement tool I found at
http://blogs.msdn.com/b/vancem/archive/2006/09/21/765648.aspx
(which runs a test method several times and displays metrics such as average time etc) I conducted a basic test, testing:

private static T GenFunc<T>() where T : class 
    {

        return dict[typeof(T)] as T;
    }

against

    private static Object ParamFunc(System.Type type)
    {
        var d = dict[type];
        return d;
    }

called as

str = GenFunc<string>();

vs

str = (String)ParamFunc(typeof(String));

respectively. Paramfunc shows a remarkable improvement in performance (executes on average in 60-70% the time it takes GenFunc) but the test is quite rudimentary and I might be missing a few things. Specifically how the casting is performed in the generic function.

An interesting aside is that there is little (neglible) performance gained by 'caching' the type in a variable and passing it to ParamFunc vs using typeof() every time.

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

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

发布评论

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

评论(2

乖乖哒 2024-12-03 01:49:32

C# 中的泛型不使用或不需要反射。

内部类型作为 RuntimeTypeHandle 值传递。 typeof 运算符映射到 Type.GetTypeFromHandle (MSDN)。在不查看 Rotor 或 Mono 进行检查的情况下,我希望 GetTypeFromHandle 的时间复杂度为 O(1) 并且非常快(例如:数组查找)。

因此,在通用 () 情况下,您实际上是将 RuntimeTypeHandle 传递到您的方法中,并在中调用 GetTypeFromHandle /em> 你的方法。在非通用情况下,您首先调用 GetTypeFromHandle,然后将结果 Type 传递到您的方法中。性能应该几乎相同 - 并且远远超过其他因素,例如您分配内存的任何位置(例如:如果您使用 params 关键字)。

但无论如何,它是一个工厂方法。每秒调用的次数肯定不会超过几次吗?还值得优化吗?

Generics in C# don't use or need reflection.

Internally types are passed around as RuntimeTypeHandle values. And the typeof operator maps to Type.GetTypeFromHandle (MSDN). Without looking at Rotor or Mono to check, I would expect GetTypeFromHandle to be O(1) and very fast (eg: an array lookup).

So in the generic (<T>) case you're essentially passing a RuntimeTypeHandle into your method and calling GetTypeFromHandle in your method. In your non-generic case you're calling GetTypeFromHandle first and then passing the resultant Type into your method. Performance should be near identical - and massively outweighed by other factors, like any places you're allocating memory (eg: if you're using the params keyword).

But it's a factory method anyway. Surely it won't be called more than a couple of times per second? Is it even worth optimising?

小镇女孩 2024-12-03 01:49:32

你总是听说反射有多慢,但在 C# 中,实际上有快反射和慢反射之分。 typeof 是快速反射 - 它基本上方法调用的开销几乎是无穷小的。

我敢打赌牛排和龙虾晚餐这不会成为您的应用程序的性能瓶颈,因此甚至不值得您(或我们)花时间尝试优化它。这句话已经被说过一百万遍了,但值得再说一遍:“过早的优化是万恶之源。”

所以,写完应用程序, 然后分析以确定瓶颈所在。如果事实证明这是其中之一,那么并且只有才需要花时间对其进行优化。请告诉我您想在哪里吃晚饭。


另外,我上面的评论值得重复,因此您不必再花时间重新发明轮子:任何像样的 IoC 容器(例如 AutoFac)都可以自动[创建工厂方法]。如果您使用其中之一,则无需编写自己的存储库,也无需编写自己的 CreateEntity() 方法,甚至无需调用 CreateEntity() 方法你自己 - 图书馆为你完成所有这一切。

You always hear how slow reflection is, but in C#, there is actually fast reflection and slow reflection. typeof is fast-reflection - it has basically the overhead of method call, which is nearly infinitesimal.

I would bet a steak and lobster dinner that this isn't going to be a performance bottleneck in your application, so it's not even worth your (or our) time in trying to optimize it. It's been said a million times before, but it's worth saying again: "Premature optimization is the root of all evil."

So, finish writing the application, then profile to determine where your bottlenecks are. If this turns out to be one of them, then and only then spend time optimizing it. And let me know where you'd like to have dinner.


Also, my comment above is worth repeating, so you don't spend any more time reinventing the wheel: Any decent IoC container (such as AutoFac) can [create factory methods] automatically. If you use one of those, there is no need to write your own repository, or to write your own CreateEntity() methods, or even to call the CreateEntity() method yourself - the library does all of this for you.

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