Note that there are some explanatory texts on larger screens.

plurals
  1. POThread-safe memoization
    text
    copied!<p>Let's take <a href="http://blogs.msdn.com/wesdyer/archive/2007/01/26/function-memoization.aspx" rel="noreferrer">Wes Dyer's</a> approach to function memoization as the starting point:</p> <pre><code>public static Func&lt;A, R&gt; Memoize&lt;A, R&gt;(this Func&lt;A, R&gt; f) { var map = new Dictionary&lt;A, R&gt;(); return a =&gt; { R value; if (map.TryGetValue(a, out value)) return value; value = f(a); map.Add(a, value); return value; }; } </code></pre> <p>The problem is, when using it from multiple threads, we can get into trouble:</p> <pre><code>Func&lt;int, int&gt; f = ... var f1 = f.Memoize(); ... in thread 1: var y1 = f1(1); in thread 2: var y2 = f1(1); // We may be recalculating f(1) here! </code></pre> <p>Let's try to avoid this. Locking on <code>map</code>:</p> <pre><code>public static Func&lt;A, R&gt; Memoize&lt;A, R&gt;(this Func&lt;A, R&gt; f) { var map = new Dictionary&lt;A, R&gt;(); return a =&gt; { R value; lock(map) { if (map.TryGetValue(a, out value)) return value; value = f(a); map.Add(a, value); } return value; }; } </code></pre> <p>is clearly a horrible idea, because it prevents us from calculating <code>f1</code> on many <em>different</em> arguments at once. Locking on <code>a</code> won't work if <code>a</code> has a value type (and at any rate is a bad idea, since we don't control <code>a</code> and outside code may lock on it, too). </p> <p>Here are two options I can think of:</p> <p>Assuming a <code>Lazy&lt;T&gt;</code> class for lazy evaluation (see <a href="http://msdn.microsoft.com/en-us/vcsharp/bb870976.aspx" rel="noreferrer">here</a>):</p> <pre><code>public static Func&lt;A, R&gt; Memoize&lt;A, R&gt;(this Func&lt;A, R&gt; f) { var map = new Dictionary&lt;A, Lazy&lt;R&gt;&gt;(); return a =&gt; { Lazy&lt;R&gt; result; lock(map) { if (!map.TryGetValue(a, out result)) { result = () =&gt; f(a); map.Add(a, result); } } return result.Value; }; } </code></pre> <p>Or keeping an additional dictionary of objects for synchronization:</p> <pre><code>public static Func&lt;A, R&gt; Memoize&lt;A, R&gt;(this Func&lt;A, R&gt; f) { var map = new Dictionary&lt;A, R&gt;(); var mapSync = new Dictionary&lt;A, object&gt;(); return a =&gt; { R value; object sync; lock(mapSync) { if (!mapSync.TryGetValue(a, out sync)) { sync = new object(); mapSync[a] = sync; } } lock(map) { if (map.TryGetValue(a, out value)) return value; } lock(sync) { value = f(a); lock(map) { map[a] = value; } return value; } }; } </code></pre> <p>Any better options?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload