Выбор ответа 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 больше никто не читает.
Варианты ответа
- Канал нужно закрыть через defer, иначе он останется открытым
- select не может ждать ctx.Done вместе с обычным каналом
- Проблемы нет: горутину соберёт GC после выхода из fetch
- При отмене ctx горутина навсегда зависнет на отправке в chправильный ответ
Разбор
При таймауте функция выходит, и из ch больше никто не читает. Горутина с slowCall повиснет на ch <- ... навсегда вместе со всем, что захватила. Исправление: буферизованный канал make(chan int, 1), тогда отправка пройдёт без читателя, или передача ctx внутрь. Закрытие канала не поможет и даже вызовет панику при отправке. select с ctx.Done стандартная конструкция.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.