← Назад к вопросам

Какие знаешь виды горутин в Go?

1.3 Junior🔥 152 комментариев
#Конкурентность и горутины

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Виды горутин в Go

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

Основная характеристика всех горутин

Все горутины — это легковесные потоки (green threads), которые:

  • Создаются со стеком небольшого размера (обычно 2 КБ, динамически растущим)
  • Планируются рантаймом Go, а не операционной системой
  • Имеют низкую стоимость создания и переключения
  • Коммуницируют через каналы (channels)
  • Являются основой конкурентной модели Go

Концептуальные категории горутин

1. Автономные (независимые) горутины

Эти горутины выполняют независимую работу и не возвращают результат напрямую.

func logWorker() {
    for {
        // Независимая фоновая работа
        time.Sleep(5 * time.Second)
        log.Println("Фоновое логирование")
    }
}

func main() {
    go logWorker() // Запуск автономной горутины
    time.Sleep(15 * time.Second)
}

2. Горутины с синхронизацией через каналы

Наиболее распространенный паттерн, где горутины координируют работу через каналы.

func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        results <- job * 2 // Возврат результата через канал
    }
}

func main() {
    jobs := make(chan int, 10)
    results := make(chan int, 10)
    
    // Запуск нескольких воркеров
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
}

3. Генераторы (производители)

Горутины, которые производят данные и отправляют их в канал.

func numberGenerator(n int) <-chan int {
    ch := make(chan int)
    go func() {
        for i := 0; i < n; i++ {
            ch <- i
        }
        close(ch)
    }()
    return ch
}

4. Pipeline-горутины

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

func processStage(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * 2 // Промежуточная обработка
        }
        close(out)
    }()
    return out
}

5. Горутины с ожиданием завершения (WaitGroup)

Группы горутин, завершение которых ожидается с помощью sync.WaitGroup.

func processBatch(data []int) {
    var wg sync.WaitGroup
    
    for _, item := range data {
        wg.Add(1)
        go func(x int) {
            defer wg.Done()
            // Обработка элемента
        }(item)
    }
    
    wg.Wait() // Ожидание завершения всех горутин
}

Специальные случаи использования

Main-горутина

Особая горутина, в которой начинается выполнение программы. Ее завершение приводит к завершению всей программы.

Системные горутины

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

Горутины с отменой контекста

Используют context.Context для graceful shutdown.

func workerWithContext(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return // Горутина завершается при отмене контекста
        default:
            // Полезная работа
        }
    }
}

Важные аспекты управления горутинами

  • Горутины-демоны — выполняются, пока работает программа (часто через select{} в конце)
  • Ограниченные горутины — используют пулы или семафоры для контроля количества
  • Горутины с восстановлением — обрабатывают паники с recover()
func safeWorker() {
    defer func() {
        if r := recover(); r != nil {
            log.Println("Восстановлено:", r)
        }
    }()
    // Работа с возможной паникой
}

Ключевые принципы работы с горутинами

  1. Горутины не являются потоками ОС — их может быть тысячи в одном процессе
  2. Коммуникация через каналы — предпочтительнее разделяемой памяти
  3. Неуправляемые горутины — антипаттерн — всегда должен быть механизм завершения
  4. Утечки горутин — серьезная проблема — нужно всегда обеспечивать выход

Заключение

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

Какие знаешь виды горутин в Go? | PrepBro