Python : Any way to get one process to have a write lock and others to just read on parallel?

前端 未结 5 1345
野的像风
野的像风 2020-12-01 09:36

Let\'s say I have a dictionary that contains key-values where the value is an object with a lock. Each process needs to get the lock to modify the specific object, but the k

5条回答
  •  醉梦人生
    2020-12-01 10:21

    One more implementation of the ReadWriteLock, takes care of the writer starvation issue and supports promotion of read lock to write lock, if requested for during construction. It utilizes only one Lock and a Condition.

    # From O'Reilly Python Cookbook by David Ascher, Alex Martelli
    # With changes to cover the starvation situation where a continuous
    #   stream of readers may starve a writer, Lock Promotion and Context Managers
    
    class ReadWriteLock:
      """ A lock object that allows many simultaneous "read locks", but
      only one "write lock." """
    
      def __init__(self, withPromotion=False):
        self._read_ready = threading.Condition(threading.RLock(  ))
        self._readers = 0
        self._writers = 0
        self._promote = withPromotion
        self._readerList = []  # List of Reader thread IDs
        self._writerList = []  # List of Writer thread IDs
    
      def acquire_read(self):
        logging.debug("RWL : acquire_read()")
        """ Acquire a read lock. Blocks only if a thread has
        acquired the write lock. """
        self._read_ready.acquire(  )
        try:
          while self._writers > 0:
            self._read_ready.wait()
          self._readers += 1
        finally:
          self._readerList.append(threading.get_ident())
          self._read_ready.release(  )
    
      def release_read(self):
        logging.debug("RWL : release_read()")
        """ Release a read lock. """
        self._read_ready.acquire(  )
        try:
          self._readers -= 1
          if not self._readers:
            self._read_ready.notifyAll(  )
        finally:
          self._readerList.remove(threading.get_ident())
          self._read_ready.release(  )
    
      def acquire_write(self):
        logging.debug("RWL : acquire_write()")
        """ Acquire a write lock. Blocks until there are no
        acquired read or write locks. """
        self._read_ready.acquire(  )   # A re-entrant lock lets a thread re-acquire the lock
        self._writers += 1
        self._writerList.append(threading.get_ident())
        while self._readers > 0:
          # promote to write lock, only if all the readers are trying to promote to writer
          # If there are other reader threads, then wait till they complete reading
          if self._promote and threading.get_ident() in self._readerList and set(self._readerList).issubset(set(self._writerList)):
            break
          else:
            self._read_ready.wait(  )
    
      def release_write(self):
        logging.debug("RWL : release_write()")
        """ Release a write lock. """
        self._writers -= 1
        self._writerList.remove(threading.get_ident())
        self._read_ready.notifyAll(  )
        self._read_ready.release(  )
    
    #----------------------------------------------------------------------------------------------------------
    
    class ReadRWLock:
      # Context Manager class for ReadWriteLock
      def __init__(self, rwLock):
        self.rwLock = rwLock
    
      def __enter__(self):
        self.rwLock.acquire_read()
        return self         # Not mandatory, but returning to be safe
    
      def __exit__(self, exc_type, exc_value, traceback):
        self.rwLock.release_read()
        return False        # Raise the exception, if exited due to an exception
    
    #----------------------------------------------------------------------------------------------------------
    
    class WriteRWLock:
      # Context Manager class for ReadWriteLock
      def __init__(self, rwLock):
        self.rwLock = rwLock
    
      def __enter__(self):
        self.rwLock.acquire_write()
        return self         # Not mandatory, but returning to be safe
    
      def __exit__(self, exc_type, exc_value, traceback):
        self.rwLock.release_write()
        return False        # Raise the exception, if exited due to an exception
    
    #----------------------------------------------------------------------------------------------------------
    

提交回复
热议问题