title: Python row-locking without WeakValueDictionary
body: <p>I want to prevent concurrent access to a dictionary on a per-element basis. Specifically, I have a <code>Cache</code> class:</p>
  
  <pre><code>class Cache:
      def __init__(self):
          self._values = {}
      def query(self, item):
          try:
              return self._values[item]
          except KeyError:
              value = compute_value(item) # Expensive operation
              self._values[item] = value
              return value
  </code></pre>
  
  <p>In words, <code>Cache</code> should compute item values on demand, then cache them for later queries.</p>
  
  <p><code>Cache</code> is used from multiple threads. I want to avoid threads concurrently calling <code>compute_value(...)</code> for the same <code>item</code>: If threads <code>A</code> and <code>B</code> both request the value for <code>my_item</code>, then only <code>A</code> should compute it. <code>B</code> should wait for its result, then use the cached value.</p>
  
  <p>I've implemented this as follows:</p>
  
  <pre><code>from threading import Lock
  from weakref import WeakValueDictionary
  
  class Cache:
      def __init__(self):
          self._values = {}
          self._locks = WeakValueDictionary()
      def query(self, item):
          with self._locks.setdefault(item, Lock()):
              try:
                  return self._values[item]
              except KeyError:
                  value = compute_value(item)
                  self._values[item] = value
                  return value
  </code></pre>
  
  <p>This works. In particular, my use of <code>WeakValueDictionary</code> ensures that concurrent queries to the same <code>item</code> get the same <code>Lock</code>, but that the locks don't stay around in memory forever.</p>
  
  <p>The problem is that my application actually creates many instances of <code>Cache</code> on the fly. Because of this, the call <code>self._values = WeakValueDictionary()</code> becomes a performance bottleneck.</p>
  
  <p>I am looking for a solution that lets me achieve the same task, but with normal Python dictionary instead of <code>WeakValueDictionary</code>. I tried:</p>
  
  <pre><code>class Cache:
      def __init__(self):
          self._values = {}
          self._locks = {} # No more WeakValueDictionary
      def query(self, item):
          with self._locks.setdefault(item, Lock()):
              # as before...
          del self._locks[item]
  </code></pre>
  
  <p>But this did not fully prevent concurrent access. Specifically, if threads <code>A</code> and <code>B</code> obtain the same lock and <code>A</code> deletes it while <code>B</code> still holds it, then another thread <code>C</code> can come along and get a <em>new</em> lock for the same row and thus access it at the same time as <code>B</code>.</p>
  
  <p>Does anyone have an idea how this could be achieved, maybe with other primitives such as semaphores?</p>