Ответ
Примитивы синхронизации — это базовые механизмы, используемые в многопоточном или многопроцессном программировании для координации доступа к общим ресурсам и предотвращения проблем, таких как состояния гонки (race conditions) и взаимоблокировки (deadlocks).
В Python модуль threading предоставляет следующие основные примитивы:
-
Lock(Блокировка)- Назначение: Самый простой примитив для обеспечения взаимного исключения. Позволяет только одному потоку одновременно выполнять критическую секцию кода.
-
Пример:
from threading import Lock shared_data = 0 lock = Lock() def increment(): global shared_data with lock: # Захватывает блокировку, гарантируя эксклюзивный доступ shared_data += 1
-
RLock(Реентерабельная блокировка)- Назначение: Позволяет одному и тому же потоку захватывать блокировку несколько раз без возникновения взаимоблокировки. Это полезно, когда функция, уже владеющая блокировкой, вызывает другую функцию, которая также пытается захватить ту же блокировку.
-
Пример:
from threading import RLock r_lock = RLock() def func1(): with r_lock: # Первый захват print("Func1 acquired lock") func2() def func2(): with r_lock: # Второй захват тем же потоком print("Func2 acquired lock")
-
Semaphore(Семафор)- Назначение: Ограничивает количество потоков, которые могут одновременно получить доступ к ресурсу или выполнить определенную секцию кода. Используется для управления пулом ресурсов.
-
Пример:
from threading import Semaphore # Разрешает до 3 потоков одновременно sem = Semaphore(3) def worker(name): import time with sem: # Захватывает семафор (уменьшает счетчик) print(f"Поток {name} работает с ресурсом...") # Имитация работы time.sleep(1) print(f"Поток {name} завершил работу.") # Семафор освобождается при выходе из 'with' (увеличивает счетчик)
-
Event(Событие)- Назначение: Простой механизм для сигнализации между потоками. Один поток ждет, пока событие не будет установлено, а другой поток устанавливает его.
-
Пример:
from threading import Event event = Event() def waiter(): print("Ожидающий поток: жду события...") event.wait() # Блокируется, пока событие не будет установлено print("Ожидающий поток: событие получено!") def setter(): import time time.sleep(2) print("Устанавливающий поток: устанавливаю событие.") event.set() # Разблокирует все ожидающие потоки
-
Condition(Условие)- Назначение: Более сложный механизм, позволяющий потокам ждать выполнения определенного условия и быть уведомленными, когда это условие становится истинным. Часто используется для реализации паттерна "производитель-потребитель".
-
Пример:
from threading import Condition items = [] condition = Condition() def producer(): with condition: # Захватывает связанный Lock items.append("item") print("Производитель: добавил элемент.") condition.notify() # Уведомляет один ожидающий поток def consumer(): with condition: # Захватывает связанный Lock while not items: # Ждем, пока условие не станет истинным print("Потребитель: жду элементы...") condition.wait() # Освобождает Lock и ждет уведомления item = items.pop(0) print(f"Потребитель: обработал {item}.")
Эти примитивы являются строительными блоками для создания надежных и эффективных многопоточных приложений, помогая управлять доступом к общим данным и координировать выполнение задач.
Ответ 18+ 🔞
А, слушай, смотри, примитивы синхронизации — это, блядь, такие базовые штуки, как молоток и гвозди в мире многопоточного программирования. Нужны они, чтобы твои потоки не устроили, сука, бардак в общих данных, не начали гоняться друг за другом, как угорелые, и не встали в позу «ты мне — я тебе», пока все не зависнет нахуй.
Вот в threading модуле у нас есть, блядь, целый арсенал. Разбираем по косточкам, чтобы ты не наебнулся.
-
Lock(Блокировка)- Зачем: Самый тупой и простой, как валенок. Позволяет только одному потоку влезть в критическую секцию, а остальным — ждать, как лохи, снаружи. Взаимное исключение, ебать его в сраку.
-
Пример:
from threading import Lock shared_data = 0 lock = Lock() def increment(): global shared_data with lock: # Захватывает блокировку, гарантируя эксклюзивный доступ shared_data += 1
-
RLock(Реентерабельная блокировка)- Зачем: А это, блядь, для умных. Если обычный
Lockзахватить дважды из одного потока — он же тебя и заблокирует, пидорас. АRLockпозволяет одному и тому же потоку захватить себя несколько раз. Удобно, когда функция внутри себя другую функцию вызывает, а та тоже лезет в тот же замок. -
Пример:
from threading import RLock r_lock = RLock() def func1(): with r_lock: # Первый захват print("Func1 acquired lock") func2() def func2(): with r_lock: # Второй захват тем же потоком print("Func2 acquired lock")
- Зачем: А это, блядь, для умных. Если обычный
-
Semaphore(Семафор)- Зачем: Это уже не «один на вход», а, блядь, «не более N на вход». Как турникет в метро в час пик. Ограничивает, сколько потоков одновременно могут к ресурсу подъебаться. Для управления пулом, например, соединений к базе.
-
Пример:
from threading import Semaphore # Разрешает до 3 потоков одновременно sem = Semaphore(3) def worker(name): import time with sem: # Захватывает семафор (уменьшает счетчик) print(f"Поток {name} работает с ресурсом...") # Имитация работы time.sleep(1) print(f"Поток {name} завершил работу.") # Семафор освобождается при выходе из 'with' (увеличивает счетчик)
-
Event(Событие)- Зачем: Проще пареной репы, ёпта. Один поток кричит: «Жди сигнала!», а другой, когда надо, бац — и сигналит. Все ждуны просыпаются и бегут дальше. Идеально для одноразовых уведомлений.
-
Пример:
from threading import Event event = Event() def waiter(): print("Ожидающий поток: жду события...") event.wait() # Блокируется, пока событие не будет установлено print("Ожидающий поток: событие получено!") def setter(): import time time.sleep(2) print("Устанавливающий поток: устанавливаю событие.") event.set() # Разблокирует все ожидающие потоки
-
Condition(Условие)- Зачем: А вот это, сука, уже серьёзная артиллерия. Тут не просто «сигнал подан», а «жди, пока выполнится условие». Классика — паттерн «производитель-потребитель». Потребитель спит, пока буфер пуст, производитель, нахуярив данных, его будит.
-
Пример:
from threading import Condition items = [] condition = Condition() def producer(): with condition: # Захватывает связанный Lock items.append("item") print("Производитель: добавил элемент.") condition.notify() # Уведомляет один ожидающий поток def consumer(): with condition: # Захватывает связанный Lock while not items: # Ждем, пока условие не станет истинным print("Потребитель: жду элементы...") condition.wait() # Освобождает Lock и ждет уведомления item = items.pop(0) print(f"Потребитель: обработал {item}.")
Вот эти все штуки, блядь, и есть фундамент, на котором можно строить что-то путнее, чем хаотичный пиздец в многопоточности. Выбирай по задаче, а то так и будешь потом дебажить race conditions, волосы на жопе рвать.