← Назад к вопросам
Какие знаешь примитивы синхронизации?
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.