golang select中break的小坑
背景:最近开了个新的rtc项目,选择了golang作为服务端的主力语言。DEMO部署上开发服务器之后,开始了愉快的调试。
过了两天同事说开发机的负载很高,要不要升级配置,登上去之后发现CPU已经满载,而且重启服务之后再测一会立刻又满载了,估计是代码里面有死循环存在。
dlv附加上去之后发现很多goroutine在死循环里面,代码有一个如下的片段:
for { select { case t:=<-tasks : t.Exec() case <-qc: break } }
一个很简单的通过quit channel控制退出的goroutine,根本没有退出。难道break只是退出select? 查阅spec后,发现:
A “break” statement terminates execution of the innermost “for”, “switch”, or “select” statement within the same function.
https://golang.org/ref/spec#Break_statements
果然如此。如果需要退出for需要使用break label的形式。关键是select里面的break意义何在,case又不会fallthrough。问题是解决了,不过有点不甘心,这么容易中招的坑不可能只有我一个人踩中吧,google一下 “golang select break” 果然,中英文问题都很多,原来大家碰到过,心理平衡点了^_^。
outloop: for { select { case t:=<-tasks : t.Exec() case <-qc: break outloop //正确的退出for循环 } }
按照stackoverflow上面的说法,select里面的break用作在case里面有较复杂的条件控制逻辑时,可以快速退出select,避免使用一堆if else,代码可读性更高。不过我想这种情况下不是把case里面的逻辑封装成函数吗,谁会在case里面搞一大坨代码。