Search code examples
c#.netmultithreadingmemoization

How to perform thread-safe function memoization in c#?


Here on stack overflow I've found the code that memoizes single-argument functions:

static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
    var d = new Dictionary<A, R>();
    return a=> 
    {
        R r;
        if (!d.TryGetValue(a, out r))
        {
            r = f(a);
            d.Add(a, r);
        }
        return r;
    };
}

While this code does its job for me, it fails sometimes when the memoized function is called from the multiple threads simultaneously: the Add method gets called twice with the same argument and throws an exception.

How can I make the memoization thread-safe?


Solution

  • You can use ConcurrentDictionary.GetOrAdd which does everything you need:

    static Func<A, R> ThreadsafeMemoize<A, R>(this Func<A, R> f)
    {
        var cache = new ConcurrentDictionary<A, R>();
    
        return argument => cache.GetOrAdd(argument, f);
    }
    

    The function f should be thread-safe itself, because it can be called from multiple threads simultaneously.

    This code also doesn't guarantee that function f is called only once per unique argument value. It can be called many times, in fact, in the busy environment. If you need this kind of contract, you should take a look at the answers in this related question, but be warned that they're not as compact and require using locks.