Ответ
В Python для синхронизации потоков в модуле threading существуют следующие основные примитивы:
-
Lock(мьютекс) — базовый механизм блокировки. Гарантирует, что только один поток может исполнять критическую секцию кода в один момент времени. Попытка захватить заблокированныйLockостановит поток до его освобождения.import threading lock = threading.Lock() with lock: # Этот код выполнит только один поток одновременно print("Критическая секция") -
RLock(реентерабельная блокировка) — позволяет одному и тому же потоку захватывать блокировку несколько раз без возникновения взаимной блокировки (deadlock). Поток должен освободитьRLockстолько же раз, сколько он его захватил. Полезна в рекурсивных функциях. -
Semaphore(семафор) — ограничивает количество потоков, которые могут одновременно получить доступ к общему ресурсу. Работает как счетчик: каждый вызовacquire()уменьшает его, аrelease()— увеличивает.# Не более 3 потоков могут выполнять этот блок одновременно semaphore = threading.Semaphore(3) with semaphore: # Работа с ограниченным ресурсом pass -
Event(событие) — простой механизм для коммуникации между потоками. Один поток может сигнализировать о событии (event.set()), а другие могут его ожидать (event.wait()). -
Condition(условие) — более сложный механизм, который объединяетLockс возможностью ожидания определенного условия. Потоки могут ждать (condition.wait()), пока другой поток не уведомит их (condition.notify()) об изменении состояния. -
Barrier(барьер) — синхронизирует выполнение группы потоков, заставляя их всех ждать в определенной точке, пока не соберутся все участники.
Для синхронизации между процессами используются аналогичные примитивы из модуля multiprocessing.
Ответ 18+ 🔞
Да ты посмотри, какие у нас в Питоне инструменты для синхронизации потоков, блядь! В модуле threading целый арсенал, просто овердохуища примитивов. Сейчас разберём, кто за что отвечает, а то потом в коде бардак будет — пиздец.
1. Lock (он же мьютекс, ёпта)
Это как самый простой замок на двери от сортира. Только один поток может зайти в критическую секцию, остальные ждут снаружи, блядь, пока первый не выйдет и не щёлкнет замком. Попробуй войти, когда занято — зависнешь, как идиот.
import threading
lock = threading.Lock()
with lock:
# Этот код выполнит только один поток одновременно
print("Критическая секция")
2. RLock (реентерабельный замок)
А это уже замок поумнее. Он позволяет одному и тому же потоку заходить в одну и ту же дверь несколько раз. Удобно, если функция вызывает сама себя (рекурсия, блядь) или дергает другие функции под тем же замком. Главное — выйти ровно столько же раз, сколько зашёл, а то сам себя заблокируешь, мудак.
3. Semaphore (семафор, сука)
Представь себе турникет в метро, который пропускает только, скажем, троих за раз. Вот семафор — он ровно это и делает. Счётчик есть, каждый поток, проходя, его уменьшает, а выходя — увеличивает. Если мест нет — жди, пока кто-то выйдет.
# Не более 3 потоков могут выполнять этот блок одновременно
semaphore = threading.Semaphore(3)
with semaphore:
# Работа с ограниченным ресурсом
pass
4. Event (событие, ёбта)
Простейший способ потокам перемигиваться. Один поток кричит: «Событие случилось!» (event.set()), а другие, которые сидели и тупили в event.wait(), вдруг просыпаются и начинают суетиться. Как будильник для спящих потоков, блядь.
5. Condition (условие, хитрая жопа)
Это уже не просто замок, а замок с интеллектом. Поток может не только захватить его, но и сказать: «Я буду ждать, пока не случится чё-то конкретное» (condition.wait()). Другой поток, сделав это «чё-то», может пихнуть первого (condition.notify()): «Эй, проснись, условие выполнилось!». Часто используется в паттернах типа «Производитель-Потребитель», там, где надо ждать появления данных.
6. Barrier (барьер, ёперный театр)
Собрал толпу потоков и заставил их всех ждать у одной черты, пока последний, самый тормозной, не подтянется. Как только все собрались — «Старт!», и они все одновременно рвут с места. Синхронный старт, блядь, для гонок.
А вот если ты работаешь не с потоками, а с процессами (это когда multiprocessing), то там, сука, всё примерно так же, только примитивы из другого модуля берутся — multiprocessing.Lock, multiprocessing.Event и так далее. Потому что память у процессов общая не через жопу, а через специальные механизмы, вот и примитивы там свои, под это дело заточенные.