Skip to content

Instantly share code, notes, and snippets.

@nycdotnet
Last active March 4, 2019 03:46
Show Gist options
  • Save nycdotnet/008ed7a417b6dca119323e25eb7aabe4 to your computer and use it in GitHub Desktop.
Save nycdotnet/008ed7a417b6dca119323e25eb7aabe4 to your computer and use it in GitHub Desktop.
ImmutableDictionary vs ReadOnlyDictionary vs Dictionary Benchmarks with .NET Core SDK 3.0-preview2
BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17134.590 (1803/April2018Update/Redstone4)
Intel Core i7-6600U CPU 2.60GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=3.0.100-preview-010184
[Host] : .NET Core 2.1.8 (CoreCLR 4.6.27317.03, CoreFX 4.6.27317.03), 64bit RyuJIT
MediumRun : .NET Core 3.0.0-preview-27324-5 (CoreCLR 4.6.27322.0, CoreFX 4.7.19.7311), 64bit RyuJIT
Job=MediumRun Toolchain=.NET Core 3.0 Preview 2 InvocationCount=1
IterationCount=15 LaunchCount=2 UnrollFactor=1
WarmupCount=10
| Method | ItemCount | Mean | Error | StdDev | Median | Rank | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|----------------------------- |---------- |--------------:|-----------:|-------------:|--------------:|-----:|------------:|------------:|------------:|--------------------:|
| ConstructDictionary | 0 | 5.366 us | 1.750 us | 2.510 us | 4.645 us | 1 | - | - | - | 72 B |
| ConstructReadOnlyDictionary | 0 | 6.456 us | 2.763 us | 3.963 us | 5.760 us | 1 | - | - | - | 112 B |
| ConstructImmutableDictionary | 0 | 5.790 us | 2.451 us | 3.516 us | 4.665 us | 1 | - | - | - | - |
| ConstructDictionary | 10 | 9.611 us | 3.122 us | 4.477 us | 7.920 us | 2 | - | - | - | 464 B |
| ConstructReadOnlyDictionary | 10 | 10.753 us | 3.213 us | 4.808 us | 9.945 us | 2 | - | - | - | 472 B |
| ConstructImmutableDictionary | 10 | 20.787 us | 4.859 us | 7.123 us | 20.700 us | 4 | - | - | - | 712 B |
| ConstructDictionary | 100 | 17.703 us | 5.834 us | 8.732 us | 13.573 us | 3 | - | - | - | 3152 B |
| ConstructReadOnlyDictionary | 100 | 16.308 us | 4.848 us | 7.107 us | 13.310 us | 3 | - | - | - | 3160 B |
| ConstructImmutableDictionary | 100 | 88.680 us | 15.268 us | 22.380 us | 80.850 us | 6 | - | - | - | 6472 B |
| ConstructDictionary | 1000 | 64.033 us | 6.319 us | 8.859 us | 60.960 us | 5 | - | - | - | 31040 B |
| ConstructReadOnlyDictionary | 1000 | 68.881 us | 10.945 us | 15.697 us | 65.830 us | 5 | - | - | - | 31048 B |
| ConstructImmutableDictionary | 1000 | 924.743 us | 78.464 us | 115.011 us | 887.775 us | 9 | - | - | - | 64072 B |
| ConstructDictionary | 10000 | 716.794 us | 124.657 us | 178.779 us | 642.448 us | 8 | - | - | - | 283040 B |
| ConstructReadOnlyDictionary | 10000 | 618.567 us | 30.743 us | 43.097 us | 612.950 us | 7 | - | - | - | 283048 B |
| ConstructImmutableDictionary | 10000 | 11,354.698 us | 943.558 us | 1,412.274 us | 11,559.440 us | 10 | - | - | - | 640072 B |
BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17134.590 (1803/April2018Update/Redstone4)
Intel Core i7-6600U CPU 2.60GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=3.0.100-preview-010184
[Host] : .NET Core 2.1.8 (CoreCLR 4.6.27317.03, CoreFX 4.6.27317.03), 64bit RyuJIT
MediumRun : .NET Core 3.0.0-preview-27324-5 (CoreCLR 4.6.27322.0, CoreFX 4.7.19.7311), 64bit RyuJIT
Job=MediumRun Toolchain=.NET Core 3.0 Preview 2 InvocationCount=1
IterationCount=15 LaunchCount=2 UnrollFactor=1
WarmupCount=10
| Method | LookupCount | Mean | Error | StdDev | Median | Rank | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|--------------------------- |------------ |---------------:|-------------:|-------------:|---------------:|-----:|------------:|------------:|------------:|--------------------:|
| DictionaryLookups | 1 | 1,253.8 ns | 698.7 ns | 956.3 ns | 827.5 ns | 1 | - | - | - | - |
| ReadOnlyDictionaryLookups | 1 | 889.0 ns | 656.1 ns | 898.0 ns | 855.0 ns | 1 | - | - | - | - |
| ImmutableDictionaryLookups | 1 | 4,287.1 ns | 2,328.6 ns | 3,413.2 ns | 2,275.0 ns | 3 | - | - | - | - |
| DictionaryLookups | 10 | 1,574.3 ns | 940.0 ns | 1,348.1 ns | 1,265.0 ns | 1 | - | - | - | - |
| ReadOnlyDictionaryLookups | 10 | 2,075.4 ns | 671.5 ns | 941.4 ns | 1,725.0 ns | 2 | - | - | - | - |
| ImmutableDictionaryLookups | 10 | 6,058.3 ns | 1,984.8 ns | 2,970.8 ns | 5,605.0 ns | 4 | - | - | - | - |
| DictionaryLookups | 100 | 6,910.6 ns | 1,509.2 ns | 2,115.8 ns | 5,905.0 ns | 4 | - | - | - | - |
| ReadOnlyDictionaryLookups | 100 | 8,153.0 ns | 2,126.4 ns | 2,980.9 ns | 6,880.0 ns | 5 | - | - | - | - |
| ImmutableDictionaryLookups | 100 | 21,223.4 ns | 3,038.1 ns | 4,357.1 ns | 19,710.0 ns | 6 | - | - | - | - |
| DictionaryLookups | 1000 | 48,210.8 ns | 3,230.2 ns | 4,834.8 ns | 47,777.5 ns | 7 | - | - | - | - |
| ReadOnlyDictionaryLookups | 1000 | 62,172.9 ns | 11,886.9 ns | 17,047.8 ns | 55,215.0 ns | 8 | - | - | - | - |
| ImmutableDictionaryLookups | 1000 | 191,542.5 ns | 28,352.2 ns | 42,436.3 ns | 174,975.0 ns | 9 | - | - | - | - |
| DictionaryLookups | 10000 | 562,560.0 ns | 138,506.9 ns | 207,310.5 ns | 486,120.0 ns | 10 | - | - | - | - |
| ReadOnlyDictionaryLookups | 10000 | 538,170.0 ns | 46,724.1 ns | 65,500.7 ns | 517,500.0 ns | 10 | - | - | - | - |
| ImmutableDictionaryLookups | 10000 | 2,157,841.7 ns | 499,166.3 ns | 731,671.4 ns | 1,759,565.0 ns | 11 | - | - | - | - |
[RankColumn, MemoryDiagnoser]
public class StringKeyDictionaryConstructionBenchmark
{
private KeyValuePair<string, int>[] _items;
[Params(0, 10, 100, 1000, 10000)]
public int ItemCount;
[IterationSetup]
public void IterationSetup()
{
_items = Enumerable
.Range(0, ItemCount)
.Select(_ => new KeyValuePair<string, int>(Guid.NewGuid().ToString(), 0))
.ToArray();
}
[Benchmark]
public Dictionary<string, int> ConstructDictionary() =>
new Dictionary<string, int>(_items);
[Benchmark]
public ReadOnlyDictionary<string, int> ConstructReadOnlyDictionary() =>
new ReadOnlyDictionary<string, int>(_items.ToDictionary(i => i.Key, i => i.Value));
[Benchmark]
public ImmutableDictionary<string, int> ConstructImmutableDictionary() =>
ImmutableDictionary.ToImmutableDictionary(_items);
}
[RankColumn, MemoryDiagnoser]
public class StringKeyDictionaryLookupBenchmark
{
private KeyValuePair<string, int>[] _items;
private int[] _result;
private Dictionary<string, int> _dictionary;
private ReadOnlyDictionary<string, int> _readOnlyDictionary;
private ImmutableDictionary<string, int> _immutableDictionary;
public int DictionarySize = 100;
[Params(1, 10, 100, 1000, 10000)]
public int LookupCount;
public void AllIterationSetup()
{
_items = Enumerable
.Range(0, DictionarySize)
.Select(_ => new KeyValuePair<string, int>(Guid.NewGuid().ToString(), 1))
.ToArray();
_result = new int[LookupCount];
}
[IterationSetup(Targets = new[] { nameof(DictionaryLookups) })]
public void SetupDictionaryLookups()
{
AllIterationSetup();
_dictionary = new Dictionary<string, int>(_items);
}
[IterationSetup(Targets = new[] { nameof(ReadOnlyDictionaryLookups) })]
public void SetupReadOnlyDictionaryLookups()
{
AllIterationSetup();
_readOnlyDictionary = new ReadOnlyDictionary<string, int>(_items.ToDictionary(i => i.Key, i => i.Value));
}
[IterationSetup(Targets = new[] { nameof(ImmutableDictionaryLookups) })]
public void SetupImmutableDictionaryLookups()
{
AllIterationSetup();
_immutableDictionary = ImmutableDictionary.ToImmutableDictionary(_items);
}
[IterationCleanup]
public void Assert()
{
if (!_result.All(v => v == 1))
{
throw new ApplicationException($"Expected all results to have been set to 1.");
}
}
[Benchmark]
public int[] DictionaryLookups() => PerformLookupsForBenchmark(_dictionary);
[Benchmark]
public int[] ReadOnlyDictionaryLookups() => PerformLookupsForBenchmark(_readOnlyDictionary);
[Benchmark]
public int[] ImmutableDictionaryLookups() => PerformLookupsForBenchmark(_immutableDictionary);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int[] PerformLookupsForBenchmark<T>(T dict) where T : IDictionary<string, int>
{
var i = 0;
while (i < LookupCount)
{
for (var j = 0; j < DictionarySize; j++)
{
_result[i] = dict[_items[j].Key];
i++;
if (i == LookupCount)
{
break;
}
}
}
return _result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment