Python условно "с" дизайн замка
Я пытаюсь сделать некоторые общие блокировки с помощью операторов
def someMethod(self, hasLock = False):
with self.my_lock:
self.somethingElse(hasLock=True)
def somethingElse(self, hasLock = False):
#I want this to be conditional...
with self.my_lock:
print 'i hate hello worlds"
Это имеет смысл? Я просто хочу сделать это, если у меня еще нет блокировки.
Вдобавок к возможности достичь этого, это плохой дизайн? Должен ли я просто приобрести/освободить себя?
Ответы
Ответ 1
Просто используйте threading.RLock
, который является повторным, что означает, что он может быть получен несколько раз тем же потоком.
http://docs.python.org/library/threading.html#rlock-objects
Для ясности, RLock
используется в операторах with
, как в вашем примере кода:
lock = threading.RLock()
def func1():
with lock:
func2()
def func2():
with lock: # this does not block even though the lock is acquired already
print 'hello world'
Что касается того, плохой дизайн или нет, нам нужен больше контекста. Почему обе функции должны приобретать замок? Когда func2
вызывается чем-то другим, кроме func1
?
Ответ 2
Python or
короткое замыкание, поэтому вы можете сделать условие блокировки:
def somethingElse(self, hasLock = False):
#I want this to be conditional...
with hasLock or self.my_lock:
print 'i hate hello worlds'
К сожалению, это не так просто, потому что логическое значение не является допустимым возвратом от оператора with
. Вам понадобится создать класс с __enter__
и __exit__
, чтобы обернуть значение boolean True
.
Вот одна из возможных реализаций, которые я не тестировал.
from contextlib import contextmanager
@contextmanager
def withTrue():
yield True
def withbool(condition):
if condition:
return withTrue()
return False
def somethingElse(self, hasLock = False):
with withbool(hasLock) or self.my_lock():
print 'i hate hello worlds'
Это много шаблонов для чего-то такого простого, поэтому решение RLock выглядит как победитель. Это решение может быть полезно в другом контексте.
Ответ 3
Почему бы и нет:
def someMethod(self):
with self.my_lock:
self.somethingNoLock()
def somethingElse(self):
with self.my_lock:
self.somethingNoLock()
def somethingNoLock(self):
print 'i hate hello worlds"
Обратите внимание, что хотя someMethod
и somethingElse
идентичны в моем решении, в общем случае они будут разными. Вы можете поместить другую обертку вокруг somethingNoLock
, чтобы сбор и освобождение блокировки не повторялись несколько раз.
Это намного проще и проще. Просто потому, что доступный молоток блокировки доступен, я бы не рекомендовал его использовать, когда есть более простой, менее хрупкий способ прибить его.
Более конкретная критика rlock заключается в том, что строка, которая создает блокировку повторного входа, находится далеко от кода, который приобретает блокировку в режиме повторного входа. Это немного хрупко, если кто-то говорит, что коалесцирует блокировку повторного входа с другой блокировкой, которая не является повторной попыткой или иным образом изменяет линию, которая создает блокировку.
Ответ 4
Использование с инструкцией лучше, чем просто функции acquire()
и release()
. Таким образом, если произошла ошибка, блокировки будут освобождены.
Ответ 5
Оператор with - отличный способ реализовать блокировку, поскольку блокировка - идеальный шаблон сбора ресурсов. Хотя ваш текущий пример не будет работать, вам понадобится оператор if вокруг инструкции with внутри somethingElse().