Hello there

My current technology stack: .NET 9, Python, TypeScript, and Azure.

I develop microservices and terraform of different sizes. Sharing my challenges and key learning.

About

The views expressed in this blog are my own and do not reflect my employer's. I am not responsible for any consequences of using the information provided. This blog is for educational purposes only, not for commercial use. Readers should apply their own judgment.

Collection Performance in .NET 9

August 12, 2024 Dipankar Haldar 25 people viewed this post

.NET 9 Performance Comparison: Hashtable vs Dictionary vs List vs Collection

.NET 9 includes several performance improvements, particularly in collections like Hashtable, Dictionary, List, and HashSet. This post compares their performance and suitability for different use cases.


Dictionary<TKey, TValue> vs Hashtable

  • Dictionary<TKey, TValue> is a generic collection that provides O(1) average-time complexity for lookups.
  • Hashtable is a non-generic collection, requiring boxing/unboxing for value types, making it less efficient.

List

  • List<T> is an ordered collection with fast index-based access but slower search times compared to hash-based structures.

Other Collections

  • ArrayList is a non-generic collection that stores objects and suffers from boxing/unboxing overhead.
  • HashSet<T> provides unique elements with fast lookups, making it useful for membership tests.

Benchmark Code

public class CollectionPerformance
{
    private Dictionary<int, int> dictionary;
    private Hashtable hashtable;
    private List<int> list;
    private HashSet<int> hashSet;
    private int searchKey = 999999;

    public void Setup()
    {
        dictionary = new Dictionary<int, int>();
        hashtable = new Hashtable();
        list = new List<int>();
        hashSet = new HashSet<int>();

        for (int i = 0; i < 1000000; i++)
        {
            dictionary[i] = i;
            hashtable[i] = i;
            list.Add(i);
            hashSet.Add(i);
        }
    }

    public void DictionaryLookup() => dictionary.ContainsKey(searchKey);

    public void HashtableLookup() => hashtable.ContainsKey(searchKey);

    public void ListLookup() => list.Contains(searchKey);

    public void HashSetLookup() => hashSet.Contains(searchKey);
}

Test Environment

  • Processor: 13th Gen Intel Core i7-1370P, 1 CPU, 20 logical and 14 physical cores
  • .NET SDK: 9.0.103
  • Runtime: .NET 9.0.2 (9.0.225.6610), X64 RyuJIT AVX2

Benchmark Results

Method Mean Error StdDev Median P95 Gen0 Allocated
DictionaryLookup 1.806 ns 0.1874 ns 0.4936 ns 1.660 ns 3.375 ns - -
HashtableLookup 9.726 ns 0.3621 ns 1.0620 ns 9.591 ns 11.761 ns 0.0019 24 B
ListLookup 112,984.793 ns 2,973.6506 ns 8,483.9931 ns 115,142.621 ns 123,135.237 ns - -
HashSetLookup 3.272 ns 0.1454 ns 0.4218 ns 3.317 ns 3.922 ns - -

Analysis & Key Takeaways

  • Dictionary<TKey, TValue> offers the best balance of speed and memory efficiency for key-based lookups.
  • Hashtable is significantly slower due to boxing/unboxing overhead and additional memory allocation.
  • List performs poorly in large datasets as it relies on O(n) linear search, making it unsuitable for frequent lookups.
  • HashSet is one of the fastest structures for lookups and ideal when uniqueness is required.

Conclusion

For most key-value lookups:

  • Use Dictionary<TKey, TValue> for the best trade-off between speed and memory.
  • Avoid Hashtable unless legacy support is required.
  • Use List only when preserving order is necessary.
  • Prefer HashSet when unique items and fast lookups are needed.