golang使用chan注意事项
背景
最近老代码中遇到的一个问题,表现为:
- goroutine数量在高峰期上涨,上涨后平峰期将不下来。也就是goroutine泄露
- 使用pprof看,进程堵塞在chan
chan的使用经验
- 在使用chan时,需要注意堵塞问题
- chan做为参数传递时,每个接收方都需要注意chan可能的堵塞(否则chan可能无法自动回收,导致gorutine无法结束)
- chan对应剩余buff为0时,则堵塞到有buffer, 或者超时
- chan应该总是和超时机制配合使用
示例代码
package main
import (
"flag"
"log"
"net/http"
_ "net/http/pprof"
"time"
"fmt"
)
func demo (){
ch := make(chan int) //1
//ch := make(chan int, 1) //2
go func() { //写chan
time.Sleep(2 * time.Second)
ch <- 0 //执行完成
}()
select {
case <-ch: //读chan
fmt.Printf("exec success\n")
return
case <- time.After(1 *time.Second):
fmt.Printf("exec timeout\n")
return
}
}
func main() {
flag.Parse()
go func() {
log.Println(http.ListenAndServe("localhost:8080", nil))
}()
for i := 0; i < 400; i++ {
go demo()
}
fmt.Printf("sleep 1hour")
time.Sleep(60 * time.Minute)
}
可以使用http://localhost:8080/debug/pprof/goroutine?debug=1查看
上面代码在(1)打开时,发生goroutine泄漏
上面代码在(2) 打开时,未发生goroutine泄漏