В Go показан такой код: "ch := make(chan int); go func(){ ch <- 1 }(); <-ch;

23 Янв в 10:44
16 +1
0
Ответы
1
Код:
ch := make(chan int)
go func(){ ch <- 1 }()
<-ch
<-ch
Анализ поведения и блокировки
- Канал создан как небуферизованный: make(chan int) — отправка блокируется до тех пор, пока кто‑то не примет значение.
- Горутинa делает одно отправление 111. Оно завершится только когда main выполнит одно чтение <−ch<-ch<ch.
- Первое чтение принимает это значение — отправившая горутина возвращается и завершается.
- Второе чтение <−ch<-ch<ch ждёт ещё одного отправления, которого не будет. В итоге все горутины блокируются — runtime выдаст panic: fatal error: all goroutines are asleep - deadlock!
Правильные способы организовать завершение/согласование
1) Принимать ровно столько раз, сколько отправляют. Если отправляется одно значение — делайте одно чтение.
2) Использовать закрытие канала, если нужно сигнализировать "больше значений не будет":
- отправляющая сторона закрывает канал:
go func(){ ch <- 1; close(ch) }()
- прием можно делать в цикле:
for v := range ch { /* v */ }
- после закрытия чтение возвращает нулевое значение и ok==false:
v, ok := <-ch; if !ok { /* канал закрыт */ }
3) Использовать сигнальный канал или sync.WaitGroup для ожидания завершения горутин:
- done := make(chan struct{})
go func(){ ch <- 1; close(done) }()
<-done // дождаться завершения
- или
var wg sync.WaitGroup
wg.Add(1)
go func(){ defer wg.Done(); ch <- 1 }()
v := <-ch
wg.Wait()
4) Буферизованный канал, если нужно, чтобы отправитель не блокировался до немедленного приёма:
- ch := make(chan int, 111)
go func(){ ch <- 1 }()
v := <-ch
// если читать больше раз, чем было отправлено, всё равно будет блокировка
5) Неблокирующие операции с select (если прием необязателен):
- select {
case v := <-ch: /* получили v */
default: /* не блокироваться */
}
Замечания/подсказки
- Закрывать канал должен только отправитель(и). Закрытие канала из нескольких мест или закрытие уже закрытого вызовет panic.
- Если вы ожидаете одноразовый сигнал о завершении — используйте chan struct{} или WaitGroup.
- Если нужно передавать набор значений одного производителя — закрывайте канал после всех отправлений и перебирайте через range.
Краткий исправленный пример (вариант с закрытием):
go func(){
ch <- 1
close(ch)
}()
for v := range ch {
_ = v
}
23 Янв в 10:51
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир