XNA/C#:实体工厂和 typeof(T) 性能
在我们的游戏(针对移动设备)中,我们有几种不同的实体类型,我正在编写一个工厂/存储库来处理新实体的实例化。每个具体实体类型都有自己的工厂实现,这些工厂由 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
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 thetypeof
operator maps toType.GetTypeFromHandle
(MSDN). Without looking at Rotor or Mono to check, I would expectGetTypeFromHandle
to be O(1) and very fast (eg: an array lookup).So in the generic (
<T>
) case you're essentially passing aRuntimeTypeHandle
into your method and callingGetTypeFromHandle
in your method. In your non-generic case you're callingGetTypeFromHandle
first and then passing the resultantType
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 theparams
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?
你总是听说反射有多慢,但在 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 theCreateEntity()
method yourself - the library does all of this for you.