TLDR: using typeof(T)
twice; assigning the value to a variable and reusing that = uber fast (30FPS), actually calling typeof(T)
twice = derped (5FPS). Why?
I have a simple entity/component system; my basic entity had an array of IComponent
s, and methods like HasComponent<T>
and GetComponent<T>
. These just iterate over the arrays and return the first matching item (this.components.Any(c => c is T)
).
Turns out a performance bottleneck I experience with 100k components "in memory" (albeit most off-screen) is actually these two methods. With a few components, no problem (30FPS+). With 100k components, just sprites, I get around 5FPS.
So I figured, why not use a Dictionary<Type, IComponent>
instead? It'll be faster, right?
Right?!
Wrong. First, a complexity: I have a SpriteComponent
class, and a SpriteSheetComponent
component class (knows about frames, animation, etc.). To simplify everything, SpriteSheetComponent
derives from SpriteComponent
. This makes drawing, ordering, etc. simpler, because of the is-a relationship.
Second, querying for components became more complex; if I ask HasComponent<SpriteComponent>
, and you have a SpriteSheetComponent
, you should return true
, right?
So the way I handle that is:
return this.components.Keys.Any(t => t == typeof(T) || t.IsSubclassOf(typeof(T)));
Ditto for fetching the element, except I use First
instead of Any
.
Anyway, I noticed that the performance actually degraded. What's even more surprising is that this fixed the performance issue:
var tType = typeof(T);
return this.components.Keys.Any(t => t == tType || t.IsSubclassOf(tType));
The only difference is that I'm checking typeof(T) once and reusing that. This fixed my FPS up to 30ish, hurrah.
But this is definitely a "lolwut" moment for me. Is typeof(T)
really that slow? And in this case, it's shredding my performance with just one extra call?
typeof
to be a red flag function, you probably call it because you have made a mess of your data structure. If you had a clean design the type would either be implicit in the code, or the difference would be handled by the objects's own methods. \$\endgroup\$ – aaaaaaaaaaaa Dec 22 '12 at 13:00typeof
would be that slow. That you are paying in speed for using a generic container is however no surprise. The thing is, you are probably also paying in some combination of code complexity, readability, and debugability. The key question is, if you want to treat the objects differently, why do you put them on the same list in the first place? \$\endgroup\$ – aaaaaaaaaaaa Dec 22 '12 at 19:00