Skip to content

Instantly share code, notes, and snippets.

@John-Paul-R
Last active January 31, 2022 18:13
Show Gist options
  • Save John-Paul-R/05e24af7f0040d302ad80fe150718133 to your computer and use it in GitHub Desktop.
Save John-Paul-R/05e24af7f0040d302ad80fe150718133 to your computer and use it in GitHub Desktop.
Comparison of `Dictionary`, `ConcurrentDictionary`, and `ImmutableDictionary` read performance at differing collection sizes.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Running;
namespace Bench_Dictionaries
{
// See https://stackoverflow.com/questions/16612936/immutable-dictionary-vs-dictionary-vs-c5
// for original source of these benchmarks.
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<Bench>();
}
}
[SimpleJob]
public class Bench
{
[Params(100, 1000, 10000, 100000)]
public int MaxItems { get; set; }
private Dictionary<string, object> _dictionary;
private ConcurrentDictionary<string, object> _concurrentDictionary;
private ImmutableDictionary<string, object> _immutableDictionary;
private string[] _randomIndicies;
[GlobalSetup]
public void GlobalSetup()
{
List<string> accessIndex = new List<string>(MaxItems);
List<KeyValuePair<string, object>> listofkvps = new List<KeyValuePair<string, object>>();
List<Tuple<string, object>> listoftuples = new List<Tuple<string, object>>();
for (int i = 0; i < MaxItems; i++) {
listoftuples.Add(new Tuple<string, object>(i.ToString(), i));
listofkvps.Add(new KeyValuePair<string, object>(i.ToString(), i));
accessIndex.Add(i.ToString());
}
// Randomize for lookups
Random r = new Random(Environment.TickCount);
List<string> randomIndexesList = new List<string>(MaxItems);
while (accessIndex.Count > 0) {
int index = r.Next(accessIndex.Count);
string value = accessIndex[index];
accessIndex.RemoveAt(index);
randomIndexesList.Add(value);
}
_randomIndicies = randomIndexesList.ToArray();
// IMMU
_immutableDictionary = listofkvps.ToImmutableDictionary();
// SCGD
_dictionary = new Dictionary<string, object>();
for (int i = 0; i < MaxItems; i++) {
_dictionary.Add(i.ToString(), i);
}
_concurrentDictionary = new ConcurrentDictionary<string, object>();
for (int i = 0; i < MaxItems; i++) {
_concurrentDictionary.TryAdd(i.ToString(), i);
}
}
[Benchmark]
public void DictionaryTest()
{
for (int index = 0, indexMax = _randomIndicies.Length; index < indexMax; index++) {
string i = _randomIndicies[index];
object value;
_dictionary.TryGetValue(i, out value);
}
}
[Benchmark]
public void ConcurrentDictionaryTest()
{
for (int index = 0, indexMax = _randomIndicies.Length; index < indexMax; index++) {
string key = _randomIndicies[index];
object value;
_concurrentDictionary.TryGetValue(key, out value);
}
}
[Benchmark]
public void ImmutableDictionaryTest()
{
for (int index = 0, indexMax = _randomIndicies.Length; index < indexMax; index++) {
string i = _randomIndicies[index];
object value;
_immutableDictionary.TryGetValue(i, out value);
}
}
}
}

netcoreapp3.1

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19042.1466 (20H2/October2020Update) AMD Ryzen Threadripper 2920X, 1 CPU, 24 logical and 12 physical cores .NET SDK=6.0.100 [Host] : .NET Core 3.1.10 (CoreCLR 4.700.20.51601, CoreFX 4.700.20.51901), X64 RyuJIT DefaultJob : .NET Core 3.1.10 (CoreCLR 4.700.20.51601, CoreFX 4.700.20.51901), X64 RyuJIT

Method MaxItems Mean Error StdDev Median
DictionaryTest 100 2.610 us 0.0194 us 0.0181 us 2.601 us
ConcurrentDictionaryTest 100 2.613 us 0.0460 us 0.0359 us 2.603 us
ImmutableDictionaryTest 100 6.512 us 0.0382 us 0.0319 us 6.513 us
DictionaryTest 1000 28.839 us 0.1055 us 0.0881 us 28.832 us
ConcurrentDictionaryTest 1000 30.251 us 0.1405 us 0.1246 us 30.197 us
ImmutableDictionaryTest 1000 84.419 us 0.4090 us 0.3415 us 84.324 us
DictionaryTest 10000 437.529 us 2.7500 us 2.4378 us 437.869 us
ConcurrentDictionaryTest 10000 448.963 us 4.5132 us 4.0008 us 448.157 us
ImmutableDictionaryTest 10000 1,200.397 us 12.9247 us 11.4574 us 1,197.821 us
DictionaryTest 100000 18,768.312 us 322.0768 us 301.2709 us 18,724.152 us
ConcurrentDictionaryTest 100000 24,238.512 us 484.3350 us 1,250.2233 us 24,286.041 us
ImmutableDictionaryTest 100000 49,022.780 us 1,851.9372 us 5,460.4786 us 51,474.082 us

net6.0

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19042.1466 (20H2/October2020Update) AMD Ryzen Threadripper 2920X, 1 CPU, 24 logical and 12 physical cores .NET SDK=6.0.100 [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

Method MaxItems Mean Error StdDev
DictionaryTest 100 1.871 us 0.0070 us 0.0059 us
ConcurrentDictionaryTest 100 1.976 us 0.0058 us 0.0051 us
ImmutableDictionaryTest 100 4.708 us 0.0293 us 0.0274 us
DictionaryTest 1000 20.777 us 0.2964 us 0.2475 us
ConcurrentDictionaryTest 1000 22.701 us 0.4386 us 0.4102 us
ImmutableDictionaryTest 1000 68.169 us 0.4853 us 0.4539 us
DictionaryTest 10000 350.626 us 6.7511 us 9.0125 us
ConcurrentDictionaryTest 10000 384.857 us 1.8929 us 1.5806 us
ImmutableDictionaryTest 10000 1,113.108 us 10.4152 us 9.7424 us
DictionaryTest 100000 16,558.332 us 330.2632 us 797.6227 us
ConcurrentDictionaryTest 100000 21,914.480 us 466.1620 us 1,374.4892 us
ImmutableDictionaryTest 100000 33,356.603 us 649.7613 us 575.9965 us

Legends

// * Legends *
  MaxItems : Value of the 'MaxItems' parameter
  Mean     : Arithmetic mean of all measurements
  Error    : Half of 99.9% confidence interval
  StdDev   : Standard deviation of all measurements
  1 us     : 1 Microsecond (0.000001 sec)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment