为啥程序会在select中被频道阻塞?
Posted
技术标签:
【中文标题】为啥程序会在select中被频道阻塞?【英文标题】:Why the program blocks by the channel in the select?为什么程序会在select中被频道阻塞? 【发布时间】:2022-01-02 15:25:17 【问题描述】:package main
import (
"fmt"
)
type A struct
exit chan bool
func (a *A) f()
select
//the routine process
//quit
case <- a.exit:
fmt.Println("-----over-----")
a.exit <- true
fmt.Println("+++++over++++++")
func main()
a := A
go a.f()
a.exit = make(chan bool)
a.exit <- true
我想运行多个 goroutine,我想让 main func 注意到其他 goroutine 退出。 这是我的代码,但是选择中的程序块,程序只输出“-----over-----”,没有“+++++over++++++”,代码有什么问题?感谢您帮助。
【问题讨论】:
把“a.exit = make(chan bool)”改成“a.exit = make(chan bool,1)”就好了 【参考方案1】:您的程序阻塞,因为这是您编写的,请考虑以下操作顺序:
main
goroutine 启动 a.f
goroutine。
a.f
阻止尝试从 nil 通道 a.exit
读取。
main
将 a.exit
设置为无缓冲通道,a.f
现在被阻止从新通道读取,这是允许的。
main
向 a.exit
写入一个值,a.f
从 a.exit
读取值,这会同步 goroutines,现在下界被阻塞。
a.f
现在阻止尝试写入无缓冲的a.exit
,这将永远不会解除阻止,因为没有人会再次尝试从通道读取。
main
现在退出并导致所有其他 goroutine 退出,这可能发生在第 5 步之前。
所以你的程序从不输出+++++over++++++
的原因是:
a.f
goroutine 在 a.exit <- true
处阻塞,因为没有其他 goroutine 会从通道中读取此值。
您的main
goroutine 可能会在a.f
完成工作之前退出并终止整个程序。
我想你是在问如何在 goroutine 完成后让 main 退出,这是最简单的例子:
package main
import (
"fmt"
)
type A struct
exit chan struct
func (a *A) f()
defer close(a.exit) // Close the chanel after f() finishes, closed channels yield the zero-value so <-a.exit will unblock
fmt.Println("+++++over++++++")
func main()
a := A
go a.f()
a.exit = make(chan struct)
<-a.exit
【讨论】:
非常感谢。我知道代码有什么问题,实际上无缓冲通道和大小为 1 的通道之间存在一些差异。在我的程序中,我这样写是因为我想运行很多af(),所以我想如果 af() 停止,它仍然会向 a.exit 通道发送一些信息,以通知其他 af() 到 quit(),所以如果我仍然想使用无缓冲通道,我可能需要添加一个 read主要功能中的频道。感谢您的帮助,我想我明白为什么它是错误的,我可以在我的代码中做什么。以上是关于为啥程序会在select中被频道阻塞?的主要内容,如果未能解决你的问题,请参考以下文章
Django 频道 - websocket_disconnect 在循环中被调用
golang [去阻塞频道]与Go#golang,#go,#go channels,#go synchronization,#goroutines,#waitgroups中的频道同步和阻止,