Классический баг. Горутина-продьюсер шлёт n значений в небуферизированный канал, а потребитель прочитал только часть и ушёл. Каждая отправка в такой канал ждёт, пока кто-нибудь примет значение. Читателя больше нет, поэтому продьюсер навсегда застрял на ch <- i. Это утечка горутины: она не завершится, и её стек останется в памяти до конца работы процесса.
Реализуйте produce так, чтобы продьюсер гарантированно завершался, даже если потребитель прочитал не всё. Потребитель сообщает «хватит», закрывая канал done.
// produce запускает горутину, которая шлёт значения 1..n в возвращаемый канал.
func produce(n int, done <-chan struct{}) <-chan int
Пример. Потребитель читает два значения из пяти и закрывает done:
done := make(chan struct{})
ch := produce(5, done)
fmt.Println(<-ch, <-ch) // 1 2
close(done) // горутина-продьюсер должна выйти, а не висеть на отправке тройки
Требования:
- Если
done не закрывали, потребитель получает все значения 1..n по порядку, затем канал закрывается. for range ch должен завершиться.
- После
close(done) горутина-продьюсер завершается, даже если она в этот момент ждёт отправки.
- Закрывать
ch должен продьюсер, а не потребитель.
Тесты запускают двадцать продьюсеров, у каждого читают по два значения из пяти, закрывают done и проверяют, что число горутин вернулось к исходному. Ещё один тест убеждается, что после close(done) продьюсер сам закрывает ch, а читатель не зависает.