Каковы ограничения на количество горутин в Go?

Ответ

В Go нет жёсткого, заранее определённого лимита на количество горутин. Однако существуют практические ограничения, которые зависят от ресурсов системы.


  • Теоретически: Можно создать миллионы горутин. Они очень легковесны, так как начальный размер стека горутины составляет всего около 2 КБ и может динамически расти и сжиматься по мере необходимости.


  • Практически: Ограничения накладываются:

    1. Оперативной памятью (RAM): Каждая горутина, даже простаивающая, потребляет память под свой стек. Миллион горутин потребует как минимум 2 ГБ RAM только для стеков.
    2. Нагрузкой на планировщик (Scheduler): С увеличением числа горутин планировщик Go тратит больше времени на управление ими, что может привести к снижению производительности.
    3. Процессорным временем (CPU): Горутины выполняются на ограниченном количестве системных потоков (по умолчанию равно количеству ядер CPU, управляется через GOMAXPROCS). Слишком большое количество активных горутин приводит к частым переключениям контекста и борьбе за ресурсы CPU.
import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    numGoroutines := 1_000_000
    for i := 0; i < numGoroutines; i++ {
        go func() {
            time.Sleep(time.Second * 10) // Просто "висим" в памяти
        }()
    }
    fmt.Printf("Успешно создано %d горутинn", numGoroutines)
    fmt.Printf("Текущее количество горутин: %dn", runtime.NumGoroutine())
    time.Sleep(time.Second * 12) // Даем время на выполнение
}

Рекомендации

Вместо бесконтрольного создания горутин рекомендуется использовать паттерны для их ограничения, например:

  • Пул воркеров (Worker Pool): Заранее создается фиксированное количество горутин-воркеров, которые разбирают задачи из канала.
  • Семафор (Semaphore): Использование взвешенного семафора (golang.org/x/sync/semaphore) для ограничения одновременного доступа к ресурсу или выполнения кода.