Jump to content
  • Advertisement
Septopus

How Smelly Is it? (c# UDP Socket Class for multiplayer game)

Recommended Posts

I can't figure out how to quote just one small section of your code block, so...

The section where you use messageDictionary.ContainsKey, Add, then [ ] operators can be condensed into a slightly more efficient form:

Queue<string> queue;
if (!messageDictionary.TryGetValue(so.epFrom, out queue)
{
    messageDictionary.Add(so.epFrom, queue = new Queue<string>());
}
queue.Enqueue(so.message);

This is a pretty common pattern in C#.

If you're using newer versions of C#, you can also say "out var queue" instead of defining the variable above TryGetValue.

Edited by Nypyren

Share this post


Link to post
Share on other sites
Advertisement

Yes!  haha, somehow I completely forgot about TryGetValue, and I've made some fairly extensive use of Dictionaries in the rest of the code... Adding this to my growing list of optimizations to rewrite later!

Thanks again!! :D

Edited by Septopus

Share this post


Link to post
Share on other sites
if (!messageDictionary.ContainsKey(so.epFrom))
{
	messageDictionary.Add(so.epFrom, new Queue<string> ());
}
messageDictionary[so.epFrom].Enqueue(so.smessage);

Okay, so here's the code we're talking about and just to make sure I understand Here's how it looks with TryGetValue:

Queue<string> queue;
if (!messageDictionary.TryGetValue(so.epFrom, out queue))
{
	messageDictionary.Add(so.epFrom, queue = new Queue<string>());
}
queue.Enqueue(so.smessage);

That seems right..

But, doesn't this create an extra pointer or something like that for the local queue variable?  I always have to ask why, when an optimization ends up taking up more lines of code. ;)

I'm not sure, but I think in THIS specific case I'm going to keep it as is.

However, the reminder about TryGetValue will probably be priceless when I hit the optimize button. ;)

Edited by Septopus

Share this post


Link to post
Share on other sites

No, you'll need a queue pointer no matter what. And pointers themselves are value types, not causing garbage collection. (The pointed-at things of course are probably not value types.)

Share this post


Link to post
Share on other sites

So, then is the second option actually more optimized?  It still seems like there is an extra reference that otherwise isn't needed...  But that's just nit-picking as far as I'm concerned...

My new question is, does TryGetValue actually cost LESS than ContainsKey?  I don't see how it could...

I think that's the biggest question for me in THIS scenario...

Never mind.. ;)

https://stackoverflow.com/questions/9382681/what-is-more-efficient-dictionary-trygetvalue-or-containskeyitem

Edited by Septopus

Share this post


Link to post
Share on other sites

This may be a better one:

https://stackoverflow.com/questions/39885203/is-there-a-reason-why-one-should-use-containskey-over-trygetvalue/39885383

But basically what I'm taking from this is since I'm accessing the queue by it's Index in the Dictionary (in the first method) it's duplicating the lookup that it's already performed with ContainsKey.

So in the second method the "extra" pointer is actually avoiding a second lookup into the Dictionary.. yes?

Sweet!  You people are wicked smart!

;)

Share this post


Link to post
Share on other sites

Basically the reason to make this specific optimization is that if you do both a ContainsKey and also an indexer (dictionary[key]) operation, the code has to find the entry (or insertion point) in the dictionary twice.  Although the entry lookup is amortized constant time (one GetHashCode call and usually one Equals call), why do it twice if you only need to do it once?

If you find yourself in a chunk of code that only needs to call ContainsKey and nothing else, keep using ContainsKey.

One neat thing you can use to judge complexity of built-in .Net code is to look at the reference source:

https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs

While it might not always be exactly what ships in .Net, it should be close enough that you can base optimization decisions on it.

Edited by Nypyren

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!