Ответ
Семафор — это примитив синхронизации, который позволяет ограничить количество горутин, одновременно выполняющих определенный участок кода или получающих доступ к определенному ресурсу. Его можно представить как счетчик, который отслеживает количество свободных "слотов".
В Go стандартная реализация семафора находится в пакете golang.org/x/sync/semaphore.
Основное назначение:
Контроль параллелизма (concurrency) для предотвращения перегрузки внешних систем (например, API с ограничением по частоте запросов, база данных с лимитом соединений) или для ограничения потребления ресурсов (памяти, CPU).
Пример использования:
Допустим, нам нужно обработать 100 задач, но мы не хотим нагружать систему и хотим выполнять не более 5 задач одновременно.
package main
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
func main() {
// Создаем семафор с "весом" 5, т.е. не более 5 горутин одновременно
sem := semaphore.NewWeighted(5)
ctx := context.Background()
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// Пытаемся "захватить" один слот. Если все заняты, горутина блокируется.
if err := sem.Acquire(ctx, 1); err != nil {
fmt.Printf("Failed to acquire semaphore: %vn", err)
return
}
// По окончании работы "освобождаем" слот
defer sem.Release(1)
fmt.Printf("Задача %d: выполняется работа...n", id)
time.Sleep(1 * time.Second)
fmt.Printf("Задача %d: работа завершена.n", id)
}(i)
}
wg.Wait()
}
Сравнение с другими примитивами:
-
Семафор vs. Mutex:
Mutex— это, по сути, бинарный семафор (с весом 1). Он предоставляет эксклюзивный доступ к ресурсу (либо занято, либо свободно).- Семафор позволяет получить доступ к ресурсу
Nгорутинам одновременно.
-
Семафор vs. Worker Pool:
- Worker Pool — это заранее созданный пул из
Nгорутин, которые ожидают задачи из канала. Количество горутин фиксировано. - Семафор не создает горутины. Он лишь ограничивает количество уже запущенных горутин, которые могут войти в критическую секцию. Это более гибкий подход, если горутины создаются динамически для выполнения короткоживущих задач.
- Worker Pool — это заранее созданный пул из
Ответ 18+ 🔞
А, семафор, говоришь? Ну это ж классика, блядь! Представь себе, сука, очередь в сортир на каком-нибудь концерте, ёпта. Всего три кабинки, а желающих обоссаться — дохуя. Вот семафор — это такой мужик с палкой на входе, который пускает внутрь только троих, а остальные, блядь, ждут, пока кто-то выйдет и освободит место. Всё просто, как три копейки!
В Гошке, правда, стандартного такого мужика в коробке нет, надо брать со стороны, из golang.org/x/sync/semaphore. Но он норм, работает.
Зачем это, нахуй, нужно? Ну, например, ты лезешь в какую-нибудь апишку, а она тебе: «Не больше пяти запросов в секунду, а то по ебалу накостыляю!». Или база данных: «Больше десяти коннектов одновременно — я сяду, и вы все сядете!». Вот тут-то наш мужик с палкой и пригодится. Он не даст всем твоим горутинам-распиздяям одновременно вломиться куда не надо.
Смотри, как это выглядит в коде:
Допустим, у тебя двадцать задач, но одновременно ты хочешь, чтобы в работе было не больше пяти. Остальные пусть постоят, подумают о жизни.
package main
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
func main() {
// Вот он, наш вышибала. Вес 5 — значит, пускает пятерых.
sem := semaphore.NewWeighted(5)
ctx := context.Background()
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// Пытаемся пройти. Acquire — это типа «эй, мужик, можно я?»
// Если мест нет — стой и не дыши, пока кто-то не выйдет.
if err := sem.Acquire(ctx, 1); err != nil {
fmt.Printf("Не пустил, сука: %vn", err)
return
}
// Выходя — ОБЯЗАТЕЛЬНО крикни «Release!», а то другие так и будут ждать.
defer sem.Release(1)
fmt.Printf("Задача %d: начинаю ебашить...n", id)
time.Sleep(1 * time.Second) // Делаем вид, что работаем
fmt.Printf("Задача %d: всё, готово, пиздец.n", id)
}(i)
}
wg.Wait() // Ждём, пока все горутины закончат свои дела
}
Чем он не является, блядь?
- Семафор vs Мьютекс: Мьютекс — это как сортир на одного. Или занято, или свободно. А семафор — это именно на несколько дырок. Если семафор с весом 1 — да, это почти мьютекс, но, блядь, с нюансами.
- Семафор vs Воркер-пул: Воркер-пул — это когда ты заранее нанял пятерых работяг (горутин) и кидаешь им задачи в канал. А семафор — это когда горутины сами понабежали, как тараканы, а ты им просто не даёшь всем сразу в одну миску лезть. Гибче, блядь, в некоторых случаях.
Короче, инструмент простой, но охуенно полезный, когда нужно придушить свой же собственный разгоняющийся код, чтобы он не сломал всё вокруг. Пользуйся на здоровье, ебать!