Why running visual studio 2019 with the debugger attached slows down concurrent dictionnary using Lazy

120 Views Asked by At

I am using concurrent dictionary to implement a simple cache but when I am running with the debugger attached visual studio the concurrent dictionary with Lazy CacheConcurrentWithLazy becomes really slow versus the CacheWithoutLazy.

  • running without the debugger attached it takes around 8000 milliseconds for either cache running the following loop.

    • lazy 9008 milliseconds
    • non-lazy 8960 milliseconds
  • running with the debugger attached it takes more than 20000 milliseconds + to run the CacheConcurrentWithLazy one.

    • lazy 19779 milliseconds
    • non-lazy 9001 milliseconds

I have tried different debug configuration but can't find a way to fix this problem.

I use visual studio 2019, .Net framework 4.8

To reproduce the problem just new to create a new console app with .net framework 4.8 and copy the following code

Run with the debugger attached -> F5

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp3
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var ts = new Stopwatch();
            ts.Start();
            
            var cacheConcurrentWithLazy = new CacheConcurrentWithLazy<int, double>(FunctionExample());
            
            for (var i = 0; i < 100000; i++) Console.WriteLine(cacheConcurrentWithLazy[i]);

            ts.Stop();
            
            var ts2 = new Stopwatch();
            ts2.Start();

            var cache = new CacheWithoutLazy<int, double>(FunctionExample());

            for (var i = 0; i < 100000; i++) Console.WriteLine(cache[i]);

            ts2.Stop();
            
            Console.WriteLine($"lazy {ts.ElapsedMilliseconds} ms");
            Console.WriteLine($"non lazy {ts2.ElapsedMilliseconds} ms");

            Console.ReadKey();
        }

        private static Func<int, double> FunctionExample()
        {
            Func<int, double> missing = x => 1.0D;
            return missing;
        }
    }

    public class CacheConcurrentWithLazy<TKey, TValue>
    {
        private readonly Func<TKey, TValue> _onMissing;

        private readonly ConcurrentDictionary<TKey, Lazy<TValue>> _values;

        private CacheConcurrentWithLazy(ConcurrentDictionary<TKey, Lazy<TValue>> dictionary,
                                        Func<TKey, TValue> onMissing)
        {
            _onMissing = OnMissing;
            _values = dictionary;
            _onMissing = onMissing;
        }

        public CacheConcurrentWithLazy(Func<TKey, TValue> onMissing) : this(
            new ConcurrentDictionary<TKey, Lazy<TValue>>(), onMissing)
        {
        }

        public TValue this[TKey key]
        {
            get
            {
                return _values.GetOrAdd(key,
                    new Lazy<TValue>(() => _onMissing(key), LazyThreadSafetyMode.ExecutionAndPublication)).Value;
            }
        }

        private TValue OnMissing(TKey key)
        {
            throw new KeyNotFoundException($"Key '{key}' could not be found");
        }
    }

    public class CacheWithoutLazy<TKey, TValue>
    {
        private readonly Func<TKey, TValue> _onMissing;

        private readonly ConcurrentDictionary<TKey, TValue> _values;

        private CacheWithoutLazy(ConcurrentDictionary<TKey, TValue> dictionary, Func<TKey, TValue> onMissing)
        {
            _onMissing = OnMissing;
            _values = dictionary;
            _onMissing = onMissing;
        }

        public CacheWithoutLazy(Func<TKey, TValue> onMissing) : this(new ConcurrentDictionary<TKey, TValue>(), onMissing)
        {
        }

        public TValue this[TKey key]
        {
            get
            {
                return _values.GetOrAdd(key, _onMissing(key));
            }
        }

        private TValue OnMissing(TKey key)
        {
            throw new KeyNotFoundException($"Key '{key}' could not be found");
        }
    }
}
0

There are 0 best solutions below