我正在建立一个由三个goroutine组成的链,每个goroutine都有一个输入输出通道。 goroutine将从输入通道读取,直到它关闭,递增值,将其发送到输出通道。但是,下面的程序会以此输出死锁:
goroutine 'one': 1
goroutine 'two': 2
goroutine 'three': 3
goroutine 'one': 10
goroutine 'two': 11
goroutine 'one': 100
fatal error: all goroutines are asleep - deadlock!
代码:
package main
import (
"fmt"
)
func int_channel(id string, i chan int, o chan int) {
defer close(o)
for x := range i {
fmt.Printf("goroutine '%s': %d\n", id, x)
o <- x + 1
}
fmt.Println("done")
}
func main() {
c0 := make(chan int)
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
go int_channel("one", c0, c1)
go int_channel("two", c1, c2)
go int_channel("three", c2, c3)
c0 <- 1
c0 <- 10
c0 <- 100
c0 <- 1000
c0 <- 10000
c0 <- 100000
close(c0)
fmt.Println("Sent all numbers to c0")
for x := range c3 {
fmt.Printf("out: %d\n", x)
}
}
答案 0 :(得分:4)
它挂起是因为从输出通道读取的循环从未到达,因此通道不会被清空&#34;并且一旦每个通道都有写入的值,就无法取得进展并且程序挂起。要修复它,请写入另一个goroutine中的输入,即
func main() {
c0 := make(chan int)
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
go int_channel("one", c0, c1)
go int_channel("two", c1, c2)
go int_channel("three", c2, c3)
go func(){
c0 <- 1
c0 <- 10
c0 <- 100
c0 <- 1000
c0 <- 10000
c0 <- 100000
fmt.Println("Sent all numbers to c0")
close(c0)
}()
for x := range c3 {
fmt.Printf("out: %d\n", x)
}
}
IOW,当执行第c0 <- 1
行时,该值会在所有三个通道中流动并最终在c3
中,但由于还没有到达读取器循环,它只是&#34;坐着在那里&#34;。然后执行第c0 <- 10
行,此值最终在c2
中,因为它无法写入c3
- 前一个值仍在那里,阻止写入。因此,当执行第c0 <- 100
行时,所有通道都已满,无法进一步进展。
答案 1 :(得分:1)
您没有及时阅读c3
。您向c0
发送了太多的值。所以渠道之间的沟通就像这样:
send 1 on c0 => recv 1 on c1 => send 2 on c2 =>
recv 2 on c2 => send 3 on c3 => recv 3 on c3
send 10 on c0 => recv 10 on c1 => send 11 on c2 =>
recv 11 on c2 => send 12 on c3 -- // c3 still hasn't been read
// from and so send
// operation blocks here.
c0,c1和c2继续接收,直到所有发送最终阻止。您可以参考以下@ ain的答案获得解决方案。