Ответ
Мьютекс и семафор — это примитивы синхронизации, используемые для управления доступом к общим ресурсам в многопоточной среде. Их ключевое различие заключается в назначении и механизме работы.
Мьютекс (Mutex - Mutual Exclusion)
Назначение: Обеспечить взаимное исключение. Мьютекс гарантирует, что только один поток может получить доступ к критической секции кода или ресурсу в любой момент времени.
Принцип работы: Работает как двоичный замок (заблокирован/разблокирован). Если ресурс свободен, поток захватывает мьютекс и блокирует его. Другие потоки, пытающиеся захватить тот же мьютекс, будут заблокированы до тех пор, пока владелец его не освободит.
Ключевая особенность: Концепция "владения". Только тот поток, который захватил мьютекс, может его освободить.
from threading import Lock, Thread
# В Python мьютекс представлен классом Lock
lock = Lock()
shared_resource = 0
def task():
global shared_resource
for _ in range(100000):
lock.acquire() # Захват мьютекса
try:
shared_resource += 1 # Критическая секция
finally:
lock.release() # Освобождение мьютекса
# Запуск потоков...
Семафор (Semaphore)
Назначение: Ограничить доступ к ресурсу определенным количеством потоков.
Принцип работы: Работает как счетчик. При инициализации семафору задается начальное значение (например, 5), которое означает, что 5 потоков могут одновременно получить доступ к ресурсу. Каждый раз, когда поток захватывает семафор, счетчик уменьшается. Когда он освобождает — увеличивается. Если счетчик равен нулю, новые потоки блокируются.
Типы:
- Счетный семафор (counting semaphore): счетчик > 1.
- Двоичный семафор (binary semaphore): счетчик равен 1, по поведению очень похож на мьютекс.
from threading import Semaphore, Thread
import time
# Ограничиваем доступ к ресурсу тремя потоками одновременно
semaphore = Semaphore(3)
def access_resource(thread_id):
print(f"Поток {thread_id} пытается получить доступ...")
with semaphore: # Автоматический acquire/release
print(f"Поток {thread_id} получил доступ!")
time.sleep(2)
print(f"Поток {thread_id} освобождает ресурс.")
# Запуск 5 потоков, но одновременно работать будут только 3
threads = [Thread(target=access_resource, args=(i,)) for i in range(5)]
for t in threads: t.start()
Сравнительная таблица
| Критерий | Мьютекс (Mutex) | Семафор (Semaphore) |
|---|---|---|
| Назначение | Взаимное исключение (защита ресурса) | Ограничение доступа (контроль параллелизма) |
| Кол-во потоков | Только один | N (заданное число) |
| Владение | Принадлежит потоку, который его захватил | Не имеет концепции владения |
| Аналогия | Ключ от одной туалетной комнаты | Набор из N ключей от одинаковых душевых кабинок |
Ответ 18+ 🔞
А, ну вот, опять про эти ваши мьютексы и семафоры. Сидишь такой, пишешь код, всё вроде летает, а потом — бац! — и два потока одновременно лезут в одну переменную, как два мудака в одну дверь. И всё, пиздец, приехали, данные похерились. Вот для этого и придумали всю эту хуйню — синхронизацию.
Так, слушай сюда, разбираем по косточкам.
Мьютекс, он же замок, он же «не лезь, пока я не отпирану»
Представь себе сортир на вокзале. Одна кабинка, один ключ. Это и есть мьютекс, ёпта. Взаимное исключение — звучит умно, а на деле: «Я щас тут сру, вы все снаружи ждите, пока я не выйду и ключ не верну».
Главная фишка — владение. Тот, кто ключ взял, тот его и должен вернуть. Чужой поток не может прийти и сказать: «А ну-ка откройся!» — нихуя. Только хозяин.
Вот смотри, как это в коде выглядит, простейший пример:
from threading import Lock, Thread
lock = Lock() # Вот он, наш ключ от сортира
shared_resource = 0 # А это наша общая заветная переменная, которую все хотят потрогать
def task():
global shared_resource
for _ in range(100000):
lock.acquire() # Берём ключ. Если ключа нет — стоишь и тупишь в стену.
try:
shared_resource += 1 # Всё, зашли в кабинку, делаем свои делишки.
finally:
lock.release() # Выходим, вешаем ключ обратно. Всё, следующий!
Если не использовать lock, то эти 100 тысяч инкрементов из разных потоков превратятся в пиздец и бардак, и в итоге получится не 200 тысяч, а какая-то рандомная хуйня. А так — порядок, один за другим.
Семафор, он же «пустите троих, остальные ждите»
А теперь представь не сортир, а, блядь, душевые в спортзале. Их, допустим, три штуки. Вот семафор — это как раздача ключей от этих душевых. Изначально у тебя на крючке висит три ключа (Semaphore(3)).
Поток приходит, берёт ключ (acquire) — счётчик ключей уменьшается. Пока он моется, другие могут взять оставшиеся два. Но как только ключей не осталось — всё, образовывается очередь, жди, пока кто-то не вернёт ключ (release).
from threading import Semaphore, Thread
import time
# Допустим, у нас есть какой-то ресурс, который может выдержать только 3 подключения одновременно
semaphore = Semaphore(3)
def access_resource(thread_id):
print(f"Поток {thread_id} подошёл к раздевалке...")
with semaphore: # Автоматически берём ключ, а потом возвращаем
print(f"Поток {thread_id} урвал ключ и пошёл мыться!")
time.sleep(2) # Представь, что тут какая-то полезная работа
print(f"Поток {thread_id} вышел, ключ на место.")
# Запускаем 5 потоков-грязнуль
threads = [Thread(target=access_resource, args=(i,)) for i in range(5)]
for t in threads: t.start()
Увидишь, что первые три потока сразу зайдут, а четвёртый и пятый будут ждать, пока кто-то не освободит кабинку. Красота, да? Это и есть ограничение параллелизма, а не просто запрет.
Так в чём, блядь, разница-то? Сравниваем
| Критерий | Мьютекс (Замок от одной кабинки) | Семафор (Набор ключей от душевых) |
|---|---|---|
| Суть | «Никого, кроме меня!» | «Пустите N человек!» |
| Кто внутри | Один поток, и всё. | N потоков (сколько ключей, столько и людей). |
| Чей ключ? | Только тот, кто взял, может вернуть. Владение. | А похуй, кто взял. Может один взять, а другой вернуть (но так делать — идиотизм). |
| Аналогия | Один туалет на всех. | Три душевые кабинки на очередь. |
Короче, если тебе нужно, чтобы к куску памяти или коду в один момент времени прикасалась только одна сущность — бери мьютекс. Если у тебя есть, условно, пул соединений к базе данных на 10 штук и ты хочешь, чтобы не больше 10 потоков одновременно их использовали, а остальные ждали — вот тут твой выход, семафор.
Вот и вся магия. Не такой уж и ёперный театр, правда? Главное — понять, что тебе нужно: полная изоляция или просто регулировка потока.