Jest to jeden z przykładów, gdzie widzę zastosowanie:
Przydatne gdy
chcesz mieć threadsave dostępu spoza klasy i używać tych samych metod od wewnątrz klasy :
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 threadsave!
with self.lock:
self.changeA() # a usual lock would block in here
self.changeB()
dla rekursji bardziej oczywiste:
lock = threading.RLock()
def a(...):
with lock:
a(...) # somewhere inside
inne wątki muszą czekać aż do pierwszego wezwania a
wykończeń = własności wątek.
Wydajność
Zazwyczaj zaczynam programowanie z zamka i gdy przypadek 1 lub 2 wystąpić, przełączyć do RLock. Until Python 3.2 RLock powinien być nieco wolniejszy z powodu dodatkowego kodu. Wykorzystuje blokady:
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()
Własność Temat
w danym wątku można nabyć RLock
tak często, jak chcesz. Inne wątki muszą poczekać, aż wątki ponownie zwrócą zasób.
To różni się od Lock
, co implikuje "funkcję wywołania funkcji" (nazwałbym to w ten sposób): Inne wywołanie funkcji musi czekać, aż zasób zostanie zwolniony przez ostatnią funkcję blokowania, nawet jeśli jest w tym samym thread = nawet jeśli jest wywoływana przez inną funkcję.
Kiedy używać blokady zamiast RLock
Po dokonaniu połączenia z zewnątrz zasobów, których nie można kontrolować.
Poniższy kod zawiera dwie zmienne: A i B, a RLock są używane aby upewnić się, 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
W changeAandB2
Blokada byłoby właściwej decyzji, chociaż nie blokuje.Lub można go poprawić za pomocą błędów przy użyciu RLock._is_owned()
. Funkcje takie jak changeAandB2
może wystąpić podczas wdrożyliśmy wzorca obserwator lub wydawca abonenta i dodać blokowania później.
Zobacz również http://stackoverflow.com/questions/8720783/recursive-locks i http://stackoverflow.com/questions/187761/recursive-lock-mutex-vs-non-recursive-lock-mutex –