Skip to content

Instantly share code, notes, and snippets.

@AArnott
Last active May 11, 2022 08:33
Show Gist options
  • Save AArnott/6666dd68e1686130d467e970fdd68011 to your computer and use it in GitHub Desktop.
Save AArnott/6666dd68e1686130d467e970fdd68011 to your computer and use it in GitHub Desktop.
The .NET Concurrent collections are often used as a thread-safe version of the ordinary collections. But they are *far* slower and heavier on GC pressure than simply adding a `lock` around use of the ordinary collections. Avoid the concurrent collections except in highly concurrent scenarios where you see high lock contention and therefore may b…
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
var ordinary = RunTest(OrdinaryDictionaryRun);
var concurrent = RunTest(ConcurrentDictionaryRun);
Console.WriteLine($"Concurrent time: {concurrent.Elapsed}, GC pressure: {concurrent.BytesAllocated}");
Console.WriteLine($"Ordinary time: {ordinary.Elapsed}, GC pressure: {ordinary.BytesAllocated}");
}
private static void OrdinaryDictionaryRun()
{
var dictionary = new Dictionary<int, int>();
for (int i = 0; i < 10000; i++)
{
lock (dictionary)
{
dictionary.TryAdd(i, 0);
}
}
for (int i = 0; i < 10000; i++)
{
lock (dictionary)
{
dictionary.Remove(i);
}
}
}
private static void ConcurrentDictionaryRun()
{
var concurrentDictionary = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 10000; i++)
{
concurrentDictionary.TryAdd(i, 0);
}
for (int i = 0; i < 10000; i++)
{
concurrentDictionary.TryRemove(i, out int _);
}
}
private static (TimeSpan Elapsed, long BytesAllocated) RunTest(Action action)
{
GC.Collect();
long memoryBefore = GC.GetAllocatedBytesForCurrentThread();
var timer = Stopwatch.StartNew();
action();
timer.Stop();
long memoryAfter = GC.GetAllocatedBytesForCurrentThread();
return (timer.Elapsed, memoryAfter - memoryBefore);
}
}
@AArnott
Copy link
Author

AArnott commented Jul 14, 2020

On my machine, the output is:

Concurrent time: 00:00:00.0042209, GC pressure: 1189752
Ordinary time:   00:00:00.0005162, GC pressure:  258040

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment