Выбор ответа Middle Горутины и планировщик GMP спрашивают часто обновлено

Утечка горутины на канале

Вопрос

В чём проблема функции?

func fetch(ctx context.Context) (int, error) {
    ch := make(chan int)
    go func() { ch <- slowCall() }()
    select {
    case v := <-ch:
        return v, nil
    case <-ctx.Done():
        return 0, ctx.Err()
    }
}

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

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

Варианты ответа

  1. Канал нужно закрыть через defer, иначе он останется открытым
  2. select не может ждать ctx.Done вместе с обычным каналом
  3. Проблемы нет: горутину соберёт GC после выхода из fetch
  4. При отмене ctx горутина навсегда зависнет на отправке в chправильный ответ

Разбор

При таймауте функция выходит, и из ch больше никто не читает. Горутина с slowCall повиснет на ch <- ... навсегда вместе со всем, что захватила. Исправление: буферизованный канал make(chan int, 1), тогда отправка пройдёт без читателя, или передача ctx внутрь. Закрытие канала не поможет и даже вызовет панику при отправке. select с ctx.Done стандартная конструкция.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.