下面这段代码会把cpu跑满
func main() {
var ch chan int
for {
select {
case <-ch:
return
default:
}
}
}
对于select语句,每个case的IO事件都是阻塞的,监听IO事件是不会占用CPU至满的。造成CPU占用的原因是这个空default,因为当case的条件不满足时,循环将会走default,然后执行下一个循环,这就造成了死循环,因此在使用for-select语句的时候不能定义空的default
通过pprof http方法分析
go tool pprof -http=:9091 profile
方框越大代表函数执行的时间越久
通过命令行分析
localhost :: ~/Desktop » go tool pprof profile 1 ↵
File: cronservice
Type: cpu
Time: Mar 8, 2023 at 5:39pm (CST)
Duration: 1.10s, Total samples = 1.47s (133.21%)
Entering interactive mode (type "help" for commands, "o" for options)
使用top排序分析
(pprof) top
Showing nodes accounting for 1.47s, 100% of 1.47s total
flat flat% sum% cum cum%
0.51s 34.69% 34.69% 0.77s 52.38% runtime.chanrecv
0.48s 32.65% 67.35% 1.25s 85.03% runtime.selectnbrecv
0.26s 17.69% 85.03% 0.26s 17.69% runtime.empty (inline)
0.21s 14.29% 99.32% 1.46s 99.32% cronservice/internal/biz.(*CronTabHandler).Run
0.01s 0.68% 100% 0.01s 0.68% runtime.casgstatus
0 0% 100% 1.46s 99.32% cronservice/internal/biz.(*TaskBiz).ListenTaskStart.func1
0 0% 100% 0.01s 0.68% runtime.gopreempt_m
0 0% 100% 0.01s 0.68% runtime.goschedImpl
0 0% 100% 0.01s 0.68% runtime.mcall
使用list func函数名 具体分析某一个函数
(pprof) list runtime.selectnbrecv
Total: 1.47s
ROUTINE ======================== runtime.selectnbrecv in /usr/local/go/src/runtime/chan.go
480ms 1.25s (flat, cum) 85.03% of Total
. . 702:// if selected, ok = selectnbrecv(&v, c); selected {
. . 703:// ... foo
. . 704:// } else {
. . 705:// ... bar
. . 706:// }
130ms 130ms 707://
240ms 1.01s 708:func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected, received bool) {
110ms 110ms 709: return chanrecv(c, elem, false)
. . 710:}
. . 711:
. . 712://go:linkname reflect_chansend reflect.chansend
. . 713:func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
. . 714: return chansend(c, elem, !nb, getcallerpc())
可以看到从底层来说问题就出现708和709行
最简单的解决办法默认分支default 里面休眠几秒
链接: