何时以及如何使用Python的RLock [英] When and how to use Python's RLock
问题描述
在阅读Python文档时,我遇到了RLock
.
有人可以举例说明一种情况吗,其中 RLock
优于 Lock
?
特别参考:
-
RLock
的递归级别".这有什么用? -
RLock
对象的线程所有权" - 性能?
这是我看到用法的一个示例:
在以下时间有用
-
您想从类外部进行线程安全访问,并从类内部使用相同的方法:
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()
-
对于递归更为明显:
lock = threading.RLock() def a(...): with lock: a(...) # somewhere inside
其他线程必须等到第一次调用
a
完成=线程所有权.
性能
通常,我开始使用Lock进行编程,当发生情况1或2时,我切换到RLock. 直到Python 3.2 ,RLock应该会慢一些由于附加的代码.它使用Lock:
Lock = _allocate_lock # line 98 threading.py
def RLock(*args, **kwargs):
return _RLock(*args, **kwargs)
class _RLock(_Verbose):
def __init__(self, verbose=None):
_Verbose.__init__(self, verbose)
self.__block = _allocate_lock()
线程所有权
在给定线程中,您可以根据需要经常获取RLock
.其他线程需要等待,直到该线程再次释放资源.
这与Lock
不同,后者暗示函数调用所有权"(我这样称呼):另一个函数调用必须等待,直到最后一个阻塞函数释放了该资源,即使该资源位于即使其他函数调用了相同的线程,也是如此.
何时使用Lock代替RLock
当您无法控制的资源外部呼叫时.
下面的代码具有两个变量:a和b,并且应使用RLock来确保a == b * 2
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
在changeAandB2
中,锁定确实会阻止,但它是正确的选择.或者可以使用RLock._is_owned()
进行错误增强.当您实现了观察者模式或发布者-订阅者并在之后添加锁定后,可能会发生诸如changeAandB2
之类的功能.
Reading through the Python docs I came across RLock
.
Can someone explain to me (with example) a scenario in which RLock
would be preferred to Lock
?
With particular reference to:
RLock
's "recursion level". How is this useful?- A threads "ownership" of an
RLock
object - Performance?
This is one example where I see the use:
Useful when
you want to have thread-safe access from outside the class and use the same methods from inside the class:
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()
for recursion more obvious:
lock = threading.RLock() def a(...): with lock: a(...) # somewhere inside
other threads have to wait until the first call of
a
finishes = thread ownership.
Performance
Usually, I start programming with the Lock and when case 1 or 2 occur, I switch to an RLock. Until Python 3.2 the RLock should be a bit slower because of the additional code. It uses Lock:
Lock = _allocate_lock # line 98 threading.py
def RLock(*args, **kwargs):
return _RLock(*args, **kwargs)
class _RLock(_Verbose):
def __init__(self, verbose=None):
_Verbose.__init__(self, verbose)
self.__block = _allocate_lock()
Thread Ownership
within the given thread you can acquire a RLock
as often as you like. Other threads need to wait until this thread releases the resource again.
This is different to the Lock
which implies 'function-call ownership'(I would call it this way): Another function call has to wait until the resource is released by the last blocking function even if it is in the same thread = even if it is called by the other function.
When to use Lock instead of RLock
When you make a call to the outside of the resource which you can not control.
The code below has two variables: a and b and the RLock shall be used to make sure a == b * 2
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
In changeAandB2
the Lock would be the right choice although it does block. Or one can enhance it with errors using RLock._is_owned()
. Functions like changeAandB2
may occur when you have implemented an Observer pattern or a Publisher-Subscriber and add locking afterward.
这篇关于何时以及如何使用Python的RLock的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!