背景:最近开了个新的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里面搞一大坨代码。

发表评论

电子邮件地址不会被公开。 必填项已用*标注