Python 只有一个底层锁的读写锁?
我已经使用Python的并发原语(我想!)编写了一个读写锁。我在SO或其他地方读到的每个实现似乎都使用两个锁——一个用于读取,另一个用于写入。我的实现只包含一个用于读取的监视器,但我可能遗漏了一些关键的东西——有人能确认这会起作用吗?如果是这样,使用额外的写锁有什么好处 这是一个经典的读写锁,优先选择读卡器(可能会导致写卡器饥饿)。我使用虚拟缓存来演示读写操作Python 只有一个底层锁的读写锁?,python,multithreading,concurrency,locking,Python,Multithreading,Concurrency,Locking,我已经使用Python的并发原语(我想!)编写了一个读写锁。我在SO或其他地方读到的每个实现似乎都使用两个锁——一个用于读取,另一个用于写入。我的实现只包含一个用于读取的监视器,但我可能遗漏了一些关键的东西——有人能确认这会起作用吗?如果是这样,使用额外的写锁有什么好处 这是一个经典的读写锁,优先选择读卡器(可能会导致写卡器饥饿)。我使用虚拟缓存来演示读写操作 将线程导入为t 类读写缓存(对象): 定义初始化(自): self.cache={} self.reads=0 self.read_co
将线程导入为t
类读写缓存(对象):
定义初始化(自):
self.cache={}
self.reads=0
self.read_cond=t.Condition(t.Lock())
def读取(自身,钥匙):
使用self.read_cond:#注册读取,以便写入将等待()
self.reads+=1
结果=self.cache[键]
使用self.read_cond:
self.reads-=1
如果不是self.reads:
self.read\u cond.notify\u all()
返回结果
def更新(自身、密钥、值):
使用self.read_cond:
而self.com阅读:
self.read_cond.wait()#等待读取清除
self.cache[key]=值#带读锁,更新值
您没有使用单个锁您正在使用一个锁和一个条件变量
self.read_lock = t.Condition(t.Lock())
条件变量也是并发原语。比锁更复杂的锁
注意:请不要调用条件变量对象read\u lock
编辑:
您的代码在我看来似乎是正确的,因为它解决了问题。正如你所说,这可能会使作家挨饿。这不是一个小问题。读写器背后的逻辑是读可能比写多得多一个额外的锁允许解决第二个读写器问题,在这个问题上写写器不会饿死。实际上,当有写入程序在等待资源时,读者必须等待。还有一个使用锁和条件的解决方案。处理饥饿问题,还支持从同一线程请求时将读锁提升为写锁
# 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
#----------------------------------------------------------------------------------------------------------
在哪里可以找到双锁版本的示例?@ErikR,您可以在这里找到一些示例:@ErikR,太早按回车键。见下面的问题。接受答案中的每个链接,以及pasztorpisti的答案和代码。它们要么使用两个锁,要么有某种双事件系统,在这种系统中,写入程序和读取程序在完成时都会相互发出信号。啊,是的,这很有道理——我想我实际上是在使用锁和事件。我已经重新命名了这个对象,想重新讨论一下它的正确性吗?