В чем разница между Lock и RLock

Из документов:

threading.RLock () - фабричная функция, которая возвращает новый объект блокировки повторного входа. Повторно входящая блокировка должна быть снята тем потоком, который ее приобрел. Как только поток получил блокировку повторного входа, тот же поток может получить ее снова без блокировки; поток должен выпускать его один раз за каждый раз, когда он его получил.

Я не уверен, зачем нам это нужно? В чем разница между Rlock а также Lock?

1 ответ

Решение

Основное отличие состоит в том, что Lock можно приобрести только один раз. Это не может быть получено снова, пока это не выпущено. (После того, как это было выпущено, это может быть повторно получено любым потоком).

RLock с другой стороны, может быть получен несколько раз одним потоком. Это должно быть выпущено такое же количество раз, чтобы быть "разблокированным".

Другое отличие состоит в том, что приобрел Lock может быть освобожден любым потоком, в то время как приобретенный RLock может быть освобожден только тем потоком, который его приобрел.


Вот пример, демонстрирующий почему RLock полезно время от времени. Предположим, у вас есть:

def f():
  g()
  h()

def g():
  h()
  do_something1()

def h():
  do_something2()

Скажем все f, g, а также h являются общедоступными (то есть могут вызываться напрямую внешним абонентом), и все они требуют синхронизации.

Используя LockВы можете сделать что-то вроде:

lock = Lock()

def f():
  with lock:
    _g()
    _h()

def g():
  with lock:
    _g()

def _g():
  _h()
  do_something1()

def h():
  with lock:
    _h()

def _h():
  do_something2()

В основном, так как f не могу позвонить g после получения блокировки необходимо вызвать "сырую" версию g (т.е. _g). Таким образом, вы получите "синхронизированную" версию и "сырую" версию каждой функции.

Используя RLock элегантно решает проблему:

lock = RLock()

def f():
  with lock:
    g()
    h()

def g():
  with lock:
    h()
    do_something1()

def h():
  with lock:
    do_something2()

Чтобы расширить ответ shx2, причина, по которой вы хотите использовать один против другого, может быть следующей:

Обычный Lock (мьютекс) обычно быстрее и безопаснее.

Причина использования RLockсостоит в том, чтобы избежать мертвой блокировки из-за, например, рекурсии. Например, давайте заблокируем рекурсивную факториальную функцию. (правда, несколько надуманный)

from threading import Lock

lock = Lock()

def factorial(n):
    assert n > 0
    if n == 1:
        return 1
    
    with lock:       
        out = n * factorial(n - 1)

    return out

Эта функция вызовет мертвую блокировку из-за рекурсивного вызова. Если мы используемRLockоднако вместо этого рекурсивные вызовы могут повторно входить в ту же блокировку столько раз, сколько необходимо. Отсюда и название реентерабельной (или рекурсивной) блокировки.

RLock называется рекурсивной блокировкой. По сути, это замок, который может разблокировать только держатель. В Lock любой поток может освободить.

Другие вопросы по тегам