← Назад к вопросам

Какие знаешь примитивы синхронизации?

1.7 Middle🔥 191 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Примитивы синхронизации в Python

Примитивы синхронизации — это механизмы для координации работы потоков в многопоточных приложениях. В Python они находятся в модуле threading.

1. Lock (Блокировка)

Самый простой примитив. Может находиться в двух состояниях: захвачена или свободна.

import threading

lock = threading.Lock()
shared_counter = 0

def increment():
    global shared_counter
    with lock:  # Context manager для автоматического release
        shared_counter += 1
        print(f"Counter: {shared_counter}")

threads = [threading.Thread(target=increment) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

2. RLock (Переентерабельная блокировка)

Один поток может захватить её несколько раз. Нужно столько же раз вызвать release.

rlock = threading.RLock()

def recursive_function(depth):
    with rlock:
        if depth > 0:
            print(f"Depth: {depth}")
            recursive_function(depth - 1)

recursive_function(3)

3. Semaphore (Семафор)

Счётчик, который можно уменьшать и увеличивать. Полезен для контроля доступа к ресурсам.

semaphore = threading.Semaphore(3)  # Максимум 3 одновременно

def access_resource(id):
    with semaphore:
        print(f"Thread {id} accessing resource")
        time.sleep(1)
        print(f"Thread {id} releasing resource")

threads = [threading.Thread(target=access_resource, args=(i,)) for i in range(10)]
for t in threads:
    t.start()
for t in threads:
    t.join()

4. Event (Событие)

Позволяет одним потокам сигнализировать другим о наступлении события.

event = threading.Event()

def waiter(name):
    print(f"{name} ждёт событие...")
    event.wait()  # Блокирует до set()
    print(f"{name} получил событие!")

def setter():
    time.sleep(2)
    print("Сигнализирую событие")
    event.set()

threads = [threading.Thread(target=waiter, args=(f"Waiter-{i}",)) for i in range(3)]
threads.append(threading.Thread(target=setter))
for t in threads:
    t.start()
for t in threads:
    t.join()

5. Condition (Условие)

Комбинирует lock и event. Потоки могут ждать, пока другой поток не проверит условие.

condition = threading.Condition()
data = None

def producer():
    global data
    with condition:
        data = [1, 2, 3]
        print("Данные произведены")
        condition.notify_all()  # Пробуди всех ждущих

def consumer(id):
    with condition:
        while data is None:  # while, не if!
            print(f"Consumer {id} ждёт...")
            condition.wait()
        print(f"Consumer {id} получил: {data}")

threads = [threading.Thread(target=consumer, args=(i,)) for i in range(2)]
threads.append(threading.Thread(target=producer))
for t in threads:
    t.start()
for t in threads:
    t.join()

6. Barrier (Барьер)

Блокирует потоки, пока не соберётся нужное количество.

barrier = threading.Barrier(3)

def worker(id):
    print(f"Worker {id} подошёл к барьеру")
    barrier.wait()  # Ждём пока все соберутся
    print(f"Worker {id} прошёл барьер!")

threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()

Сравнительная таблица

ПримитивНазначениеСостояния
LockВзаимоисключениезахвачена / свободна
RLockТо же, но переентерабельнаясчётчик
SemaphoreКонтроль числа потоковсчётчик
EventСигнал между потокамиset / clear
ConditionЖдание на условииlock + event
BarrierСинхронизация группысчётчик

Важные правила

  • Всегда используй with для автоматического release
  • Избегай deadlock: захватывай блокировки в одном порядке
  • В asyncio используй asyncio.Lock вместо threading.Lock
  • GIL делает threading в Python менее эффективным для CPU-bound задач

Для параллелизма CPU-bound операций используй multiprocessing, а не threading.