Если вы сначала позвоните fibonnaci, он отправит значение на канал, но получатель не готов. В этом причина тупика.
Примечание:
По умолчанию отправляет и получает блок, пока другая сторона не будет готова.
Это позволяет goroutines синхронизироваться без явных блокировок или
условные переменные.
Тем не менее, если вы хотите изменить порядок вашей программы, чтобы увидеть, как мы можем избежать тупика.
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case q:= <-quit:
fmt.Println(q)
return
}
}
}
func pp(c chan int, quit chan int){
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}
func main() {
c := make(chan int)
quit := make(chan int)
go func(){
fibonacci(c, quit)
}()
pp(c,quit)
}
Рабочий код на Игровая площадка Go
Всегда не забывайте ждать, пока рутина go закончится в таких ситуациях. Но когда вы сначала вызываете fibonnaci, он отправил значение, но получатель не готов, что приводит к тупику.
Edit:
Потому что даже если вы подождете, пока закончится рутина. Это все равно создаст тупик, потому что каналы не синхронизируются как:
основной пакет
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case q:= <-quit:
fmt.Println(q)
return
}
}
}
func pp(c chan int, quit chan int){
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}
func main() {
c := make(chan int)
quit := make(chan int)
fibonacci(c, quit)
wg.Add(1)
go pp(c,quit)
wg.Wait()
}
Выход:
фатальная ошибка: все рутины спят - тупик!
маршрут 1 [выбрать]: main.fibonacci (0x434080, 0x4340c0)
/tmp/sandbox779301309/main.go:13 + 0xc0 main.main ()
/tmp/sandbox779301309/main.go:34 + 0x80
Если вы измените свой код и создадите регистр по умолчанию в цикле выбора for. Тогда он удовлетворит этот случай и вернется, а ваш основной выйдет. Никогда не заканчивая цикл, дайте ему ждать возврата в случае выхода, чтобы он вернулся. Это будет работать:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case q, ok := <-quit:
if ok {
fmt.Println(q)
}
return
default:
fmt.Println("No value in any of the channel")
return
}
}
}
func pp(c chan int, quit chan int) {
for i := 0; i < 10; i++ {
if value, ok := <-c; ok {
fmt.Println(value)
}
}
quit <- 0
}
func main() {
c := make(chan int)
quit := make(chan int)
fibonacci(c, quit)
go pp(c, quit)
}
Пример игровой площадки