0

Essentially I'm trying to find out whether I should be storing a reference to the service I retrieve or if I can simply call GetService every time I need it.

A perfect example of what I'm using this with is SpriteBatch. Instead of having an object store a reference to the SpriteBatch, I call

    SpriteBatch spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch)); 

at the beginning of every Draw() method that needs it.

In conclusion, what is the Big O of GetService()? This will help me decide. I'm assuming it's a hash table so generally O(1)?

Sonic 4305
  • 147
  • 1
  • 2
  • 8

3 Answers3

3

The Big-O of GetService is irrelevant, because you have a small and constant number of services in there. So effectively calling GetService is a constant-time O(1) operation. (Internally it uses a Dictionary - I couldn't easily track down a definitive answer on its Big-O, but I imagine it's pretty good).

Is it a lot slower than getting a reference? Yes.

Is it too slow for a game world with, say, 100 gameplay objects? No.

Is it too slow for each of 100000 particles in a particle system? Yes.

Is using a services architecture for this a bad idea, even if you ignore performance and consider only an architectural point of view? Yes.

Community
  • 1
  • 1
Andrew Russell
  • 26,924
  • 7
  • 58
  • 104
1

Can't say I know anything about the the asymptotic efficiency of GetService, but the obvious thing is that it's guarenteed to be slower than maintaining a reference to the object. At least, this should be obvious, as a reference is just sitting there, waiting to be used, whilst GetService requires retrieving a Type instance from a class, then looking up that Type in whatever collection is used, and finally casting to the correct type, incurring runtime checks and such.

Individually, none of these things is a problem. Even all together, none of them are a problem if only used a few times. But seeing as how you are retrieving these on a per-frame basis, the hit could become apparent, depending on how many services you are retrieving each frame.

Based on the small amount of information I have about your code, I would say that changing to the reference option shouldn't be that hard. But to really decide on whether it's worth it, maybe try to switching to keeping a reference (at least for a couple of services) and checking on how much your FPS changes. Alternatively, throw in some extraneous GetService calls and see how much of a drop in FPS it causes. That would be a more definitive way to find out the importance of changing everything over.

Ken Wayne VanderLinde
  • 18,915
  • 3
  • 47
  • 72
  • I definitely know it will be slower; I am just wondering if anyone has had experience with the difference. Right now, I have no noticeable change in frame rate and I am using GetService() for many objects. I will try your idea calling GetService() multiple times. – Sonic 4305 Aug 07 '11 at 01:57
  • @Sonic Since the question revolved around efficiency, I focused on that as much as I could. But I thought that now I might throw in my two cents about good code. I think that, from a design perspective, if you expect the same object to be used throughout the lifetime of the enclosing object, then maintaining a reference makes this intent apparent. It also requires that any service retrieving code is taken out of the `Draw` method, and moved to a more appropriate method. – Ken Wayne VanderLinde Aug 07 '11 at 03:24
  • That does make a lot of sense. Thanks for the help! – Sonic 4305 Aug 08 '11 at 05:31
0

If the this instance of a SpriteBatch is something you need through your whole simulation, I think you should store it in Services. I think if you use the GameServiceContainer correctly, you don't have to bother with Speed. E.g: in my simulation I have about 20 GameServices that have to be available to lots of GameComponents. The most of these services are extracted from Services while calling Initialize(), because the instance don't change during runtime. The only Services that might change (in my simulation) are ICamera und IGlobalLight. So these are the only references that are extracted from Services on every Draw().

Finally I think the performance overhead is worth it, compared to a "architectural solution" like super global variables or making all Services Singletons.

0xBADF00D
  • 980
  • 1
  • 12
  • 25