Weighted: веса и бюджет
Генерация превью: лёгкие страницы почти ничего не стоили, а тяжёлые отчёты съедали сотни мегабайт памяти. Лимит «пять одновременных» душил лёгкие задачи и пропускал пять тяжёлых. Миша перешёл от штук к бюджету: каждая задача объявила свой вес.
взвешенный семафор меряет не число операций, а объём ресурса: каждая операция занимает свой вес, и лимит — это бюджет, а не счётчик штук.
Почему штуки не подходят
Обычный семафор считает операции штуками: каждая занимает ровно одно разрешение. Но ресурс, который мы ограничиваем, часто расходуется неравномерно. Одна задача держит соединение, другая — пятьдесят мегабайт памяти, третья — оба сразу. При лимите «5 одновременных операций» пять задач по пятьдесят мегабайт пролезут без проблем, а пять лёгких упрутся в тот же потолок, хотя могли бы работать параллельно. Нужен семафор, который меряет объём ресурса.
Бюджет в единицах ресурса
sem := semaphore.NewWeighted(100) // бюджет: 100 единиц ресурса
if err := sem.Acquire(ctx, 50); err != nil {
return err // отменены: вес не занят
}
defer sem.Release(50) // возвращаем ровно занятое
if err := sem.Acquire(ctx, 1); err != nil { // лёгкая задача на 1 единицу
return err
}
defer sem.Release(1)
Тяжёлая задача занимает половину бюджета, лёгкая — сотую. Одновременно может работать: две тяжёлые, или одна тяжёлая и пятьдесят лёгких, или сто лёгких. Лимит выражает реальный ресурс — мегабайты, соединения, токены, — а не «число горутин». Ошибку Acquire проверяют до defer Release: при отменённом контексте вес не занят, и возврат незанятого веса тихо раздул бы бюджет.
Acquire(ctx, n)
Acquire(ctx, n) ведёт себя как одиночное разрешение из прошлого урока, только с учётом веса: ждёт, пока освободится n единиц бюджета, отменяется по контексту, ничего не теряя. Release(n) возвращает ровно n — несовпадение весов с Acquire — это ошибка в коде, и про парность заботится тот же defer.
Вы узнаете:
- как выбирать единицу бюджета
- как взвешенный лимит работает для пула соединений разного калибра
Проверьте себя
Как выбрать единицу бюджета взвешенного семафора?
Что делает Weighted, если все веса равны 1?
Release больше занятого — что произойдёт?
правильных ответов
Weighted: лимит — бюджет в единицах ресурса; каждая операция объявляет свой вес; Acquire(ctx, n)/Release(n) симметричны и держатся на defer после проверки ошибки. Это concurrency limit, выраженный в ресурсе, а не в штуках.
10 000 ₽ · 60 минут · онлайн