Что произойдёт при отправке в небуферизированный channel до приёма?
Укажите, что именно делает эта программа во время выполнения (печатает что-то, молча блокируется или аварийно завершается), и объясните почему. Затем дайте однострочное исправление, после которого она печатает 1.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
Предскажите исход.
Будет deadlock: fatal error: all goroutines are asleep - deadlock!. Отправка в небуферизированный channel блокируется, пока не готов получатель, но единственная горутина заблокирована на этой отправке, поэтому приём не выполняется. Исправление: отправлять из отдельной горутины или make(chan int, 1).
- ✗Думать, что небуферизированный channel буферизует одно значение — его ёмкость ноль
- ✗Ожидать, что runtime тихо зависнет, а не сообщит
deadlock! - ✗Считать, что одна горутина может последовательно и отправить, и принять на небуферизированном channel
- →Почему runtime Go может обнаружить этот deadlock, но не тот, что связан с заблокированным syscall?
- →Как перенос отправки в
go func(){ ch <- 1 }()исправляет ситуацию?
Что произойдёт?
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
Результат
fatal error: all goroutines are asleep - deadlock!
Почему
make(chan int) создаёт небуферизированный channel (ёмкость 0). Отправка ch <- 1 синхронна: она блокируется, пока какая-то другая горутина не будет готова принять.
Здесь работает только одна горутина — main. Она встаёт на ch <- 1 и никогда не доходит до строки <-ch. Получателя нет, прогресса нет. Среда выполнения видит, что все горутины спят, и аварийно завершает программу с deadlock!.
Два исправления:
// 1) отправлять из отдельной горутины
go func() { ch <- 1 }()
fmt.Println(<-ch) // 1
// 2) буферизированный channel вмещает значение без получателя
ch := make(chan int, 1)
ch <- 1
fmt.Println(<-ch) // 1