2 回答
TA贡献1794条经验 获得超8个赞
您的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
打印在控制台上。
如果您的目的是在您的应用程序存在之前等待所有 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()
}
另一种选择是为通道提供 1 的缓冲区,这样就可以在通道上发送 1 个值,而无需准备好从通道接收的接收器(在Go Playgroundmain()
上尝试这个):
var ch1 = make(chan int, 1) var ch2 = make(chan int, 1)
有了这个,就可以在没有和 的情况main()
下继续,所以同样,不能保证您会看到任何打印内容。f1()
f2()
TA贡献2019条经验 获得超9个赞
这里使用的通道是无缓冲通道。
当主协程启动时,它会创建两个新的协程 f1 和 f2。
当执行 f1 或 f2 时,它将检查通道中是否有值,否则它将打印默认消息并退出。
在理想情况下,通道将首先发布值,然后通过 goroutine 接收它
实际情况是 Goroutine 通过打印默认情况退出,但主 Goroutine 试图在通道中发布值,但由于没有接收器,它面临死锁情况。
消除了第一个示例中的死锁,请参阅链接:https ://play.golang.org/p/6RuQQwC9JkA
但是,如果主例程退出,所有关联的 goroutine 将被自动杀死。这就是为什么我们可以看到该值是任意打印的。
删除了第二个示例中的死锁,请参阅链接:https ://play.golang.org/p/yUmc_jjZMgV
sync.WaitGroup 正在使主 goroutine 等待,这就是为什么我们可以在每次程序执行时观察到输出。
- 2 回答
- 0 关注
- 123 浏览
添加回答
举报