Thread-safe memoization

前端 未结 7 1027
庸人自扰
庸人自扰 2020-12-07 16:53

Let\'s take Wes Dyer\'s approach to function memoization as the starting point:

public static Func Memoize(this Func f)
{         


        
7条回答
  •  臣服心动
    2020-12-07 17:40

    Thomas's answer does not seem to compile under .NET 4.0 due to the enum parameter to the Lazy constructor. I revised it below. I also added an optional parameter for supplying one's own equality comparer. This is useful if TInput does not implement its own Equals or if TInput is a string and you want to make it case insensitive, for example.

        public static Func Memoize(
            this Func func, IEqualityComparer comparer = null)
        {
            var map = comparer == null
                          ? new ConcurrentDictionary>()
                          : new ConcurrentDictionary>(comparer);
    
            return input =>
                   {
                       var lazy = new Lazy(() => func(input), LazyThreadSafetyMode.ExecutionAndPublication);
    
                       return map.TryAdd(input, lazy)
                                  ? lazy.Value
                                  : map[input].Value;
                   };
        }
    

    I did some basic testing of this method using this as my test:

        public void TestMemoize()
        {
            Func mainFunc = i =>
                                         {
                                             Console.WriteLine("Evaluating " + i);
                                             Thread.Sleep(1000);
                                             return i.ToString();
                                         };
    
            var memoized = mainFunc.Memoize();
    
            Parallel.ForEach(
                Enumerable.Range(0, 10),
                i => Parallel.ForEach(Enumerable.Range(0, 10), j => Console.WriteLine(memoized(i))));
        }
    

    It seems to be working correctly.

提交回复
热议问题