R-Lock и Lock в Python
В Python, Lock
и RLock
– это примитивы синхронизации из модуля threading
, управляющие доступом к общим ресурсам в многопоточных программах. Однако их поведение и применение различаются.
Lock (threading.Lock)
Описание: Lock
– базовый механизм блокировки, разрешающий доступ только одному потоку одновременно. Остальные потоки блокируются до снятия блокировки.
Нереентерабельный: Поток, удерживающий блокировку, не может получить ее повторно, не освободив предварительно. Попытка повторного получения приведет к взаимоблокировке.
Применение: Lock
используется, когда потоку нужно получить блокировку единожды и снять ее после выполнения задачи.
Пример:
import threading
lock = threading.Lock()
def critical_section():
lock.acquire()
try:
print(f"{threading.current_thread().name} is in the critical section")
finally:
lock.release()
thread1 = threading.Thread(target=critical_section)
thread2 = threading.Thread(target=critical_section)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
R-Lock (threading.RLock)
Описание: R-Lock (Reentrant Lock, RLock
) – более продвинутый механизм, позволяющий одному потоку получать блокировку многократно без взаимоблокировки. Каждое получение должно сопровождаться освобождением.
Реентерабельный: Поток может повторно получить уже удерживаемую блокировку, но должен освободить ее соответствующее число раз.
Применение: RLock
используется, когда потоку может потребоваться многократное получение одной блокировки, например, в рекурсивных функциях или при вызове одной защищенной блокировкой операции из другой, также защищенной блокировкой.
Пример:
import threading
rlock = threading.RLock()
def recursive_function(count):
rlock.acquire()
try:
print(f"{threading.current_thread().name} acquired the lock: count = {count}")
if count > 0:
recursive_function(count - 1) # Recursive call acquires the lock again
finally:
rlock.release()
thread = threading.Thread(target=recursive_function, args=(3,))
thread.start()
thread.join()
Ключевые различия между Lock и RLock
Особенность | Lock (threading.Lock) | RLock (threading.RLock) |
Повторный вход | Нереентерабельный (взаимоблокировка при повторном захвате тем же потоком). | Реентерабельность (один и тот же поток может быть получен несколько раз). |
Вариант использования | Простые механизмы блокировки без вложенной или рекурсивной блокировки. | Рекурсивная блокировка или сценарии вложенной блокировки. |
Производительность | Немного быстрее и проще. | Немного больше накладных расходов из-за поддержки повторного входа. |
Lock или RLock: когда что применять?
Lock
подходит для простых сценариев без необходимости повторного входа. Если же предполагается, что потоку может понадобиться получить одну и ту же блокировку несколько раз, например, в рекурсивных функциях или при вложенных блокировках, следует использовать RLock
. Выбор между Lock
и RLock
зависит от специфики задачи и потенциальных сценариев взаимодействия потоков с общими ресурсами. RLock
предоставляет большую гибкость, но может незначительно снизить производительность по сравнению с Lock
в ситуациях, где реентерабельность не требуется.