Đây là một ví dụ mà tôi thấy việc sử dụng:
hữu ích khi
bạn muốn có threadsave truy cập từ bên ngoài lớp học và sử dụng các phương pháp tương tự từ bên trong lớp :
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()
để đệ quy rõ ràng hơn:
lock = threading.RLock()
def a(...):
with lock:
a(...) # somewhere inside
chủ đề khác phải đợi cho đến khi cuộc gọi đầu tiên là a
hoàn tất quyền sở hữu chuỗi.
Performance
Thường thì tôi bắt đầu lập trình với các Khóa và khi trường hợp 1 hoặc 2 xảy ra, tôi chuyển sang một RLock. Until Python 3.2 RLock sẽ chậm hơn một chút do mã bổ sung. Nó sử dụng Khóa:
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()
Chủ đề sở hữu
trong chủ đề cho bạn có thể có được một RLock
thường xuyên như bạn muốn. Các chủ đề khác cần đợi cho đến khi luồng này giải phóng tài nguyên một lần nữa.
Điều này khác với Lock
ngụ ý 'quyền sở hữu chức năng gọi' (tôi sẽ gọi theo cách này): Một cuộc gọi chức năng khác phải chờ cho đến khi tài nguyên được phát hành bởi chức năng chặn cuối cùng ngay cả khi nó ở trong cùng một thread = ngay cả khi nó được gọi bởi hàm khác.
Khi sử dụng Khóa thay vì RLock
Khi bạn thực hiện cuộc gọi ra bên ngoài của các nguồn tài nguyên mà bạn không thể kiểm soát.
Đoạn code dưới đây có hai biến: a, b và RLock được sử dụng để đảm bảo một == 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
Trong changeAandB2
Lock sẽ là lựa chọn đúng đắn mặc dù nó không block.Hoặc bạn có thể tăng cường lỗi bằng cách sử dụng RLock._is_owned()
. Các chức năng như changeAandB2
có thể xảy ra khi bạn đã triển khai mẫu Observer hoặc Publisher-Subscriber và thêm khóa sau đó.
Xem thêm http://stackoverflow.com/questions/8720783/recursive-locks và http://stackoverflow.com/questions/187761/recursive-lock-mutex-vs-non-recursive-lock-mutex –