Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save udlose/180ca444ac0de69c0703a40be06fd212 to your computer and use it in GitHub Desktop.

Select an option

Save udlose/180ca444ac0de69c0703a40be06fd212 to your computer and use it in GitHub Desktop.
Dictionary Add with key of type Guid vs string
[MemoryDiagnoser]
[Config(typeof(DictionaryKeyAddBenchmarks.DictionaryKeyAddBenchmarksConfig))]
public class DictionaryKeyAddBenchmarks
{
private readonly Consumer _consumer = new Consumer();
private Guid[] _guidKeys = Array.Empty<Guid>();
private string[] _string_20_Keys = Array.Empty<string>();
private string[] _string_50_Keys = Array.Empty<string>();
// [Params(5_000, 10_000, 50_000)]
[Params(500, 1_000, 5_000)]
public int DictionarySize { get; set; }
[GlobalSetup]
public void GlobalSetup()
{
int count = DictionarySize;
_guidKeys = new Guid[count];
for (int i = 0; i < count; i++)
{
_guidKeys[i] = Guid.NewGuid();
}
_string_20_Keys = CreateUniqueStrings(count, 20, seed: 12345);
_string_50_Keys = CreateUniqueStrings(count, 50, seed: 54321);
}
// baseline enables Ratio (relative factor)
[Benchmark(Baseline = true)]
[MethodImpl(MethodImplOptions.NoInlining)]
public void Add_Guid()
{
// use locals to avoid noise from property reads
int count = DictionarySize;
// create a new dictionary each benchmark run to avoid having to use IterationSetup
// which should NOT be used for microbenchmarks:
// https://benchmarkdotnet.org/articles/features/setup-and-cleanup.html#sample-introsetupcleanupiteration
Dictionary<Guid, int> dictionary = new Dictionary<System.Guid, int>(count);
Guid[] keys = _guidKeys;
Consumer consumer = _consumer;
for (int i = 0; i < count; i++)
{
// add throws on duplicate keys
dictionary.Add(keys[i], i);
consumer.Consume(i);
}
consumer.Consume(dictionary.Count);
}
[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public void Add_String_20()
{
// use locals to avoid noise from property reads
int count = DictionarySize;
// create a new dictionary each benchmark run to avoid having to use IterationSetup
// which should NOT be used for microbenchmarks:
// https://benchmarkdotnet.org/articles/features/setup-and-cleanup.html#sample-introsetupcleanupiteration
Dictionary<string, int> dictionary = new Dictionary<string, int>(count);
string[] keys = _string_20_Keys;
Consumer consumer = _consumer;
for (int i = 0; i < count; i++)
{
// add throws on duplicate keys
dictionary.Add(keys[i], i);
consumer.Consume(i);
}
consumer.Consume(dictionary.Count);
}
[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public void Add_String_50()
{
// use locals to avoid noise from property reads
int count = DictionarySize;
// create a new dictionary each benchmark run to avoid having to use IterationSetup
// which should NOT be used for microbenchmarks:
// https://benchmarkdotnet.org/articles/features/setup-and-cleanup.html#sample-introsetupcleanupiteration
Dictionary<string, int> dictionary = new Dictionary<string, int>(count);
string[] keys = _string_50_Keys;
Consumer consumer = _consumer;
for (int i = 0; i < count; i++)
{
// add throws on duplicate keys
dictionary.Add(keys[i], i);
consumer.Consume(i);
}
consumer.Consume(dictionary.Count);
}
private static string[] CreateUniqueStrings(int count, int length, int seed)
{
HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
string[] result = new string[count];
Random random = new Random(seed);
//const string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
int alphabetLength = alphabet.Length;
for (int i = 0; i < count; i++)
{
while (true)
{
char[] chars = new char[length];
for (int c = 0; c < length; c++)
{
chars[c] = alphabet[random.Next(alphabetLength)];
}
string candidate = new string(chars);
if (seen.Add(candidate))
{
result[i] = candidate;
break;
}
}
}
return result;
}
private class DictionaryKeyAddBenchmarksConfig : ManualConfig
{
public DictionaryKeyAddBenchmarksConfig()
{
SummaryStyle = BenchmarkDotNet.Reports.SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend);
}
}
}
public static class Program
{
public static void Main(string[] args)
{
BenchmarkRunner.Run<DictionaryKeyAddBenchmarks>();
}
}
// Run time: 00:09:49 (589.97 sec), executed benchmarks: 9
//
// * Summary *
// BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7628/25H2/2025Update/HudsonValley2)
// AMD Ryzen 9 7945HX with Radeon Graphics 2.50GHz, 1 CPU, 32 logical and 16 physical cores
//
// .NET SDK 10.0.102
// [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v4
//
//| Method | DictionarySize | Mean | Error | StdDev | Median | Ratio | RatioSD |
//|-------------- |--------------- |-----------:|----------:|----------:|-----------:|-------------:|--------:|
//| Add_Guid | 500 | 2.596 μs | 0.0560 μs | 0.1578 μs | 2.568 μs | baseline | |
//| Add_String_20 | 500 | 4.801 μs | 0.0959 μs | 0.1915 μs | 4.798 μs | 1.86x slower | 0.13x |
//| Add_String_50 | 500 | 7.329 μs | 0.1669 μs | 0.4733 μs | 7.179 μs | 2.83x slower | 0.25x |
//| | | | | | | | |
//| Add_Guid | 1000 | 4.961 μs | 0.0989 μs | 0.2518 μs | 4.897 μs | baseline | |
//| Add_String_20 | 1000 | 8.864 μs | 0.1769 μs | 0.4307 μs | 8.849 μs | 1.79x slower | 0.12x |
//| Add_String_50 | 1000 | 14.653 μs | 0.6094 μs | 1.7485 μs | 13.979 μs | 2.96x slower | 0.38x |
//| | | | | | | | |
//| Add_Guid | 5000 | 91.310 μs | 1.8140 μs | 3.7462 μs | 91.167 μs | baseline | |
//| Add_String_20 | 5000 | 111.300 μs | 2.2225 μs | 6.1215 μs | 111.078 μs | 1.22x slower | 0.08x |
//| Add_String_50 | 5000 | 138.318 μs | 2.7604 μs | 5.7620 μs | 138.342 μs | 1.52x slower | 0.09x |
// Run time: 00:11:12(672.18 sec), executed benchmarks: 9
//
// * Summary *
// BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7628/25H2/2025Update/HudsonValley2)
// AMD Ryzen 9 7945HX with Radeon Graphics 2.50GHz, 1 CPU, 32 logical and 16 physical cores
//
// [Host] : .NET Framework 4.8.1 (4.8.9221.0), X86 LegacyJIT
// DefaultJob : .NET Framework 4.8.1 (4.8.9221.0), X86 LegacyJIT
//
//| Method | DictionarySize | Mean | Error | StdDev | Median | Ratio | RatioSD |
//|-------------- |--------------- |-----------:|----------:|-----------:|-----------:|-------------:|--------:|
//| Add_Guid | 500 | 6.566 μs | 0.1643 μs | 0.4660 μs | 6.564 μs | baseline | |
//| Add_String_20 | 500 | 7.771 μs | 0.2117 μs | 0.6107 μs | 7.570 μs | 1.19x slower | 0.13x |
//| Add_String_50 | 500 | 9.999 μs | 0.1988 μs | 0.4685 μs | 9.980 μs | 1.53x slower | 0.13x |
//| | | | | | | | |
//| Add_Guid | 1000 | 12.915 μs | 0.2508 μs | 0.2788 μs | 12.908 μs | baseline | |
//| Add_String_20 | 1000 | 13.723 μs | 0.2575 μs | 0.3349 μs | 13.753 μs | 1.06x slower | 0.03x |
//| Add_String_50 | 1000 | 20.643 μs | 0.5156 μs | 1.4457 μs | 20.194 μs | 1.60x slower | 0.12x |
//| | | | | | | | |
//| Add_Guid | 5000 | 110.310 μs | 2.2023 μs | 5.8018 μs | 108.866 μs | baseline | |
//| Add_String_20 | 5000 | 108.083 μs | 2.6184 μs | 7.5128 μs | 107.593 μs | 1.03x faster | 0.09x |
//| Add_String_50 | 5000 | 157.940 μs | 5.4328 μs | 15.7615 μs | 158.477 μs | 1.44x slower | 0.16x |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment