Ответ
Семафор — это примитив синхронизации, который позволяет ограничить количество горутин, одновременно выполняющих определенный участок кода или получающих доступ к определенному ресурсу. Его можно представить как счетчик, который отслеживает количество свободных "слотов".
В 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 — это заранее созданный пул из