Skip to content

Instantly share code, notes, and snippets.

@copernicus365
Created October 21, 2014 18:07
Show Gist options
  • Save copernicus365/df386f7fd581e5577895 to your computer and use it in GitHub Desktop.
Save copernicus365/df386f7fd581e5577895 to your computer and use it in GitHub Desktop.
Test performance of a Dictionary with enum key, against Dictionary with int key
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace EnumTest
{
/// <summary>
/// Test to discover how well enum lookups are handled in a Dictionary.
/// Is it a lot faster to work with an int instead?
/// I.e.
/// <![CDATA[
/// Dictionary<int, xyz> instead of Dictionary<MyCoolEnum,xyz> ?
/// ]]>
/// RESULTS! To my surprise, not only does the enum-dictionary
/// (dictionary with a enum as its key) perform as fast as when an interger
/// is its key, it even edges it out by a bit. WIth an integer dict,
/// to do lookups we have to cast the enum to an int, but: 1) I thought that
/// would be incredibly fast, and perfectly optimized by the compiler anyways,
/// and 2) the enum dict would internally need to do this anyways. My HOPE
/// was that .NET team had basically done this under the hood, cast enums
/// to int for you, making them of identical performance. Well somehow they
/// even edge that out by a tiny bit. So this is very good news. Never again
/// be timid about setting an enum as a Dictionary key, when focused on best
/// lookup speeds.
/// </summary>
public class TestEnumDict
{
public int Count;
public Eval[] types;
public int typesLen;
public Dictionary<int, Eval> intDict;
public Dictionary<Eval, Eval> enumDict;
Eval[] typesArray;
Eval lastVal;
public TestEnumDict(int count)
{
Count = count;
intDict = new Dictionary<int, Eval>();
enumDict = new Dictionary<Eval, Eval>();
types = Enum.GetValues(typeof(Eval)).Cast<Eval>().ToArray(); // XEnum<Eval>.Values;
// SKIP last value (make sure enum has at least 4 vals) so we can ensure optimizations later don't mess results
lastVal = types.Last();
types = types.Take(types.Length - 1).ToArray();
typesLen = types.Length;
foreach (Eval type in types) {
intDict[(int)type] = type;
enumDict[type] = type;
}
typesArray = new Eval[Count];
for (int i = 0, j = 0; i < typesArray.Length; i++) {
if (j >= typesLen) j = 0;
typesArray[i] = types[j++];
}
}
public static void TestRun()
{
int count = 1000; // 10 million
var test = new TestEnumDict(count);
var result1 = test.RunRoundToString();
var result2 = test.RunRoundToString();
var result3 = test.RunRoundToString();
var result4 = test.RunRoundToString();
var result5 = test.RunRoundToString();
var result6 = test.RunRoundToString();
Console.ReadLine();
}
public string RunRoundToString()
{
var val = RunRound();
return string.Format("EnumDict Run: {0}ms\r\nIntDict Run: {1}ms", val.Key.TotalMilliseconds, val.Value.TotalMilliseconds);
}
public KeyValuePair<TimeSpan, TimeSpan> RunRound()
{
var sw = Stopwatch.StartNew();
int len = typesArray.Length;
for (int i = 0; i < len; i++) {
Eval val = enumDict[typesArray[i]];
if (val == lastVal)
throw new Exception();
}
TimeSpan enumDictTime = sw.Elapsed;
Console.WriteLine("RUN EnumDict: {0}ms", enumDictTime.TotalMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < len; i++) {
Eval val = intDict[(int)typesArray[i]];
if (val == lastVal)
throw new Exception();
}
TimeSpan intDictTime = sw.Elapsed;
Console.WriteLine("RUN IntDict: {0}ms", intDictTime.TotalMilliseconds);
return new KeyValuePair<TimeSpan, TimeSpan>(enumDictTime, intDictTime);
}
}
public enum Eval
{
Val01, Val02, Val03, Val04, Val05, Val06,
//Val07, Val08, Val09, Val10, Val11, Val12,
//Val13, Val14, Val15, Val16, Val17, Val18,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment