Ответ
В Go нет жёсткого, встроенного в язык ограничения на количество горутин. Теоретически, их можно создать миллионы. Практический лимит определяется объемом доступной оперативной памяти (RAM).
Ключевые аспекты:
- Легковесность: Каждая горутина начинается с небольшого стека (около 2 КБ), который может динамически расти и сжиматься по мере необходимости. Это делает их гораздо дешевле системных потоков.
- Потребление памяти: Несмотря на легковесность, каждая горутина всё же потребляет память. Создание миллионов горутин может потребовать гигабайты RAM, и при исчерпании памяти программа аварийно завершится с ошибкой
out of memory
. - Нагрузка на планировщик: Очень большое количество горутин (миллионы) создает дополнительную нагрузку на планировщик Go, который должен управлять их состоянием, что может незначительно снизить производительность.
Практические рекомендации:
- Для I/O-bound задач (сетевые запросы, работа с файлами), где горутины часто ожидают, можно и нужно создавать большое их количество (тысячи, десятки тысяч).
- Для CPU-bound задач (математические вычисления), идеальное количество активных горутин обычно равно количеству ядер процессора (
runtime.GOMAXPROCS(0)
). Для таких задач часто используют паттерн Worker Pool, чтобы ограничить параллелизм и избежать лишних переключений контекста.
Пример создания миллиона горутин:
import (
"fmt"
"runtime"
"time"
)
func main() {
numGoroutines := 1_000_000
for i := 0; i < numGoroutines; i++ {
go func() {
time.Sleep(time.Second) // Симуляция работы
}()
}
fmt.Printf("Successfully created %d goroutines.n", numGoroutines)
fmt.Printf("Current number of goroutines: %dn", runtime.NumGoroutine())
time.Sleep(2 * time.Second) // Дать время горутинам завершиться
}