Что напечатает этот цикл select по channel ёмкости 1?
Предскажите вывод и скажите, что изменится, если бы ch был небуферизированным.
func main() {
ch := make(chan int, 1)
for i := 0; i < 10; i++ {
select {
case x := <-ch:
print(x)
case ch <- i:
}
}
}
Объясните вывод и небуферизированный случай.
Печатает 02468. С ёмкостью 1 на одной goroutine ветки отправки и приёма чередуются: при пустом буфере готова лишь отправка (кладёт i, ничего не печатает); на следующей итерации буфер полон, поэтому готов лишь приём (печатает сохранённое чётное значение). С небуферизированным channel ни одна ветка никогда не готова на одной goroutine, поэтому это fatal error: all goroutines are asleep - deadlock.
- ✗Думать, что один проход
selectможет и отправить, и принять по одному channel - ✗Забывать, что небуферизированный channel блокирует обе ветки, вызывая deadlock
- ✗Называть deadlock восстановимой panic, а не фатальной runtime-ошибкой
- →Почему самая первая итерация ничего не печатает, а не
0? - →Почему
all goroutines are asleep - deadlock— фатальная ошибка, а неpanic, которую можноrecover?
Что выведет
02468.
Канал буферизирован ёмкостью 1, и весь код в одной goroutine. В select ветка готова, только если соответствующая операция может выполниться немедленно:
i=0: буфер пуст → приём не готов, отправка готова. Кладём0. Печати нет.i=1: буфер полон ([0]) → отправка не готова, приём готов. Печатаем0, буфер пуст.i=2: буфер пуст → кладём2.i=3: буфер полон ([2]) → печатаем2.- … и так далее → печатаются
0, 2, 4, 6, 8.
Небуферизированный случай
Если заменить на make(chan int), в одной goroutine ни одна ветка не готова: отправке некому передать, приёму неоткуда взять. select без default блокируется, все goroutine спят:
fatal error: all goroutines are asleep - deadlock!
Это фатальная ошибка рантайма, а не panic — её нельзя поймать через recover.