select case break引发的血案

最近线上一个模块有内存泄漏,加了http pprof后,发现goroutine一直在增长,怀疑是goroutine泄漏导致的内存泄漏。于是死看代码,发现以下代码片段可能存在问题:

//goroutine
...
for{
    select {
        case ...
            ...
        case ...
            ...
        case <- exitChan:
            break;
    }
}

代码逻辑中,当socket关闭的时候会往exitChan发送数据,这个时候以上代码中的goroutine就需要跳出for循环,结束该goroutine。
问题就出在break上,这里的break是跳出case,还是跳出for?翻书,select-case没有break,所以我应该是写代码的时候以为这个break会跳出for循环。不能确认,那就写个代码测试一下。

package main

import (
	"fmt"
	"time"
)

var exitChan chan bool

func Waiting1(){
	defer func(){
		fmt.Println("waiting1 exit")
	}()
	//do someting
	time.Sleep(time.Second *10)
	exitChan <- true
}

func Waiting2(){
	defer func(){
		fmt.Println("waiting2 exit")
	}()
	for{
		select {
		case <-time.After(time.Second * 2):
			fmt.Println("tick event...")
		case <- exitChan:
			fmt.Println("exit event...")
			break
		}
	}
	
	
}


func main(){
	exitChan = make(chan bool)
	go Waiting1()
	go Waiting2()
	<- time.After(time.Second * 60)
	fmt.Println("main return")

}

运行结果告诉我,select-case下的break果然只是跳出了select的分支,跟C语言中的switch-case一样。只不过C语言中,明确要求要break,而Go则没有要求。
所以,这回stupid了一回,赶紧检查一下其他代码,发现其他select-case的分支,如果要跳出for,都是用的return。可能当时写代码的时候脑袋进了水吧…

你可能感兴趣的:(GO学习)