class X:
def __init__(self):
self.a = 1
self.b = 2
self.lock = threading.RLock()
def changeA(self):
with self.lock:
self.a = self.a + 1
def changeB(self):
with self.lock:
self.b = self.b + self.a
def changeAandB(self):
# you can use chanceA and changeB thread-safe!
with self.lock:
self.changeA() # a usual lock would block at here
self.changeB()
import threading
a = 0
b = 0
lock = threading.RLock()
def changeAandB():
# this function works with an RLock and Lock
with lock:
global a, b
a += 1
b += 2
return a, b
def changeAandB2(callback):
# this function can return wrong results with RLock and can block with Lock
with lock:
global a, b
a += 1
callback() # this callback gets a wrong value when calling changeAandB2
b += 2
return a, b
这是一个我看到使用的例子:
在
您希望从类外部具有线程安全访问权限,并从类内部使用相同的方法:
对于更明显的递归:
其他线程必须等到
a
的第一次调用完成=线程所有权。性能
通常,我用锁开始编程,当情况1或2发生时,我切换到RLock。Until Python 3.2由于有额外的代码,RLock应该慢一点。它使用锁:
线程所有权
在给定的线程中,您可以随时获取
RLock
。其他线程需要等到该线程再次释放资源。这与
Lock
不同,后者意味着“函数调用所有权”(我会这样调用):另一个函数调用必须等到最后一个阻塞函数释放资源,即使它在同一线程中=即使它被另一个函数调用。何时使用Lock而不是RLock
当您呼叫无法控制的资源外部时。
下面的代码有两个变量:a和b,使用RLock确保a==b*2
在
changeAandB2
中,尽管锁确实会阻塞,但它是正确的选择。或者可以使用RLock._is_owned()
错误地增强它。当您实现了观察者模式或发布者订阅服务器并在之后添加锁定时,可能会发生类似changeAandB2
的函数。这是RLock的另一个用例。假设您有一个支持并发访问的面向web的用户界面,但是您需要管理对外部资源的某些访问。例如,您必须保持内存中的对象和数据库中的对象之间的一致性,并且您有一个管理器类来控制对数据库的访问,其中的方法必须确保按特定顺序调用,而不能同时调用。
你能做的是创建一个RLock和一个守护线程,它通过不断获取RLock来控制对它的访问,并且只有在发出信号时才释放。然后,确保所有需要控制访问权限的方法在运行之前获得锁。像这样的:
这样,您就可以确保以下几点:
基元锁(lock)是一种同步基元,锁定时不属于特定线程。
对于处于锁定状态的可重复锁(RLock),某些线程拥有该锁;在解锁状态下,没有线程拥有该锁。 如果此线程已经拥有锁,则调用时,将递归级别增加一个,然后立即返回。如果线程不拥有锁,它将等待所有者释放锁。 释放锁,降低递归级别。如果减量为零,则将锁重置为解锁。
我不认为有什么性能上的差异,而是概念上的差异。
相关问题 更多 >
编程相关推荐