2 回答

TA贡献1779条经验 获得超6个赞
您的main()函数尝试在所有通道上发送,并且只有一次尝试在单独的并发 goroutine 中从这些通道中读取。这是否成功取决于 goroutine 调度程序。如果非阻塞接收f2()比发送更早安排main(),那么后面的发送main()将永远阻塞(没有人会再次尝试接收ch2)。
摆脱死锁的一种方法是使用接收操作而不是非阻塞接收(在Go Playground上尝试):
func f1() {
<-ch1
fmt.Println("ch1")
}
func f2() {
<-ch2
fmt.Println("ch2")
}
因此,无论何时main()在这些通道上发送值,总会有一个接收器准备好继续,所以main()不会卡住。
请注意,当main()返回时,应用程序结束,它不会等待非主 goroutine 完成。因此,您可能无法在控制台上看到ch1和打印。ch2有关详细信息,请参阅Go 中的 goroutine 没有输出。
如果您的意图是在您的应用程序存在之前等待所有 goroutine 完成它们的工作,请使用sync.WaitGroup它(在Go Playground上尝试):
var ch1 = make(chan int)
var ch2 = make(chan int)
var wg sync.WaitGroup
func f1() {
defer wg.Done()
<-ch1
fmt.Println("ch1")
}
func f2() {
defer wg.Done()
<-ch2
fmt.Println("ch2")
}
func main() {
wg.Add(1)
go f1()
wg.Add(1)
go f2()
ch1 <- 1
ch2 <- 2
wg.Wait()
}
在此处查看更多示例:解决 goroutines 死锁;并防止 main() 函数在 goroutine 在 Golang 中完成之前终止。
另一种选择是为通道提供 1 的缓冲区,因此main()可以在没有接收器准备好从通道接收的情况下在通道上发送 1 值(在Go Playground上试试这个):
var ch1 = make(chan int, 1)
var ch2 = make(chan int, 1)
有了这个,可以在没有and的main()情况下继续,所以再一次,不能保证你会看到任何打印出来的东西。f1()f2()

TA贡献1784条经验 获得超7个赞
此处使用的通道是无缓冲通道。
当 main goroutines 启动时,它会创建两个新的 goroutine f1 和 f2。
当执行 f1 或 f2 时,它将检查我们是否在通道中有值,否则它将打印默认消息并退出。
理想情况下,channels 会先发布值,然后通过 goroutine 接收
实际情况是 goroutine 通过打印默认情况退出,但主 goroutine 试图在通道中发布值,但由于没有接收器,它面临死锁情况。
从第一个示例中删除了死锁,请参考链接: https: //play.golang.org/p/6RuQQwC9JkA
但是,如果 main 例程退出,所有关联的 goroutine 将被自动终止。这就是为什么我们可以看到该值是任意打印的。
从第二个示例中删除了死锁,请参阅链接: https: //play.golang.org/p/yUmc_jjZMgV
sync.WaitGroup 正在让 main goroutine 等待,这就是为什么我们可以在每次程序执行时观察输出。
- 2 回答
- 0 关注
- 154 浏览
添加回答
举报