Go Academy · Урок

Ограничение горутин

Управляйте параллелизмом

Урок 3 из 413 шагов

«Ограничение горутин» — бесплатный урок Go Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.

Ограничение параллелизма

Иногда нужно ограничивать не число операций в секунду, а количество горутин, работающих одновременно. Это ограничивает одновременную нагрузку на ресурс независимо от времени выполнения операций.

  • Ограничивает параллелизм
  • Защищает пулы соединений
  • Предотвращает скачки потребления памяти

Канал-семафор

Буферизованный канал работает как счётный семафор. Его вместимость равна максимальному уровню параллелизма. При захвате в канал отправляется токен, а при освобождении один токен из него принимается.

sem := make(chan struct{}, 3)

Захват и освобождение

Перед началом работы отправьте значение в канал, чтобы захватить слот (если канал заполнен, операция блокируется). После завершения работы примите значение из канала, чтобы освободить слот для другой горутины.

sem <- struct{}{}        // acquire
// do work
<-sem                    // release

Почему struct{}

Пустая структура struct{}{} занимает ноль байт. Использование её в качестве элемента канала превращает семафор в чистый сигнал без лишних затрат памяти.

Ограничение цикла

Запускайте горутину для каждой задачи, но пропускайте каждую через семафор. Одновременно реальную работу выполняет не более cap горутин; остальные блокируются при захвате.

for _, task := range tasks {
    sem <- struct{}{}
    go func(t Task) {
        defer func() { <-sem }()
        process(t)
    }(t)
}

Использование с WaitGroup

Семафор ограничивает параллелизм, но не сообщает, когда завершатся все операции. Объедините его с sync.WaitGroup, чтобы дождаться выполнения всех задач.

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    defer func() { <-sem }()
    process(t)
}()

Освобождение через defer

Всегда освобождайте слот через defer, чтобы он освободился даже при панике или досрочном возврате из функции. Если забыть освободить слот, они будут утекать, что в итоге приведёт к взаимной блокировке новых операций захвата.

Полный запуск с ограничением

Эта программа выполняет восемь задач, одновременно запуская не более двух, и выводит сообщения о начале и завершении, чтобы показать ограничение в действии.

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    sem := make(chan struct{}, 2)
    var wg sync.WaitGroup
    for i := 0; i < 8; i++ {
        wg.Add(1)
        sem <- struct{}{}
        go func(id int) {
            defer wg.Done()
            defer func() { <-sem }()
            fmt.Println("start", id)
            time.Sleep(20 * time.Millisecond)
            fmt.Println("end", id)
        }(i)
    }
    wg.Wait()
    fmt.Println("done")
}

errgroup с SetLimit

Пакет golang.org/x/sync/errgroup предоставляет SetLimit для ограничения группы и передачи первой ошибки. Во многих случаях это более простой вариант, хотя пакет является внешним.

Ограничение параллелизма и пул работников

Пул работников повторно использует фиксированный набор горутин, извлекающих задачи из очереди. При семафорном ограничении для каждой задачи создаётся горутина, но число активных горутин ограничивается. Пулы экономнее при огромном числе задач, а семафоры проще добавить к существующему коду.

Выбор ограничения

Для обращений к базе данных установите ограничение на уровне размера пула соединений или ниже. Для исходящих запросов HTTP ориентируйтесь на ограничение соединений с узлом. Слишком высокое значение приводит к исчерпанию ресурсов, а слишком низкое — к неэффективному использованию возможностей.

Проверка знаний

Проверьте свои знания об ограничении параллелизма.

Итоги

Вы изучили ограничение числа горутин:

  • Буферизованный канал работает как счётный семафор
  • Захватывайте слот отправкой, а освобождайте через получение в defer
  • Элементы struct{} занимают ноль байт
  • Используйте WaitGroup, чтобы дождаться завершения
  • Выбирайте размер ограничения с учётом защищаемого ресурса
Можно начать бесплатно

Изучай Go с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
51
Уроки
203

Часто задаваемые вопросы

Урок «Ограничение горутин» бесплатный?

Да — полный текст урока «Ограничение горутин» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.

Чему я научусь в уроке «Ограничение горутин»?

Управляйте параллелизмом Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Go Academy?

Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Ограничение горутин»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Go Academy?

Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Концепция корзины токенов
  2. golang.org/x/time/rate
  3. Ограничение горутин
  4. Отложенный повтор
← Назад к Go Academy