Python условно "с" дизайн замка - PullRequest
17 голосов
/ 03 марта 2011

Я пытаюсь сделать общую блокировку с помощью операторов

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"

Это имеет смысл? Я просто хочу сделать это, если у меня еще нет блокировки.

Кроме того, это может быть плохой дизайн? Должен ли я просто приобрести / освободить себя?

Ответы [ 5 ]

38 голосов
/ 03 марта 2011

Просто используйте 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?

5 голосов
/ 03 марта 2011

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__, чтобы обернуть логическое значение 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 выглядит победителем.Это решение может быть полезно в другом контексте.

1 голос
/ 13 июля 2016

Почему бы и нет:

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 заключается в том, что строка, которая создает блокировку повторного входа, находится далеко от кода, который получает блокировку повторным входом. Это немного хрупко, если кто-то скажет, что объединяет повторно входящую блокировку с другой блокировкой, которая не является повторно входящей, или иным образом изменяет строку, которая создает блокировку.

0 голосов
/ 03 марта 2011

Оператор with - отличный способ реализовать блокировку, поскольку блокировка - это идеальный шаблон получения ресурсов.Хотя ваш текущий пример не сработает, вам понадобится оператор if вокруг оператора with вthingElse ().

0 голосов
/ 03 марта 2011

Использование с оператором лучше, чем просто функции acquire() и release().Таким образом, если произойдет ошибка, блокировки будут сняты.

...