查看因持有互斥锁(mutexes)导致阻塞的情况(堆栈)
使用前需要先调用 runtime.SetBlockProfileRate
。
$ go tool pprof http://localhost:6060/debug/pprof/mutex
Fetching profile over HTTP from http://localhost:6060/debug/pprof/mutex
Saved profile in /Users/weishi/pprof/pprof.contentions.delay.002.pb.gz
Type: delay
Time: Aug 15, 2020 at 1:54pm (+08)
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 0, 0% of 0 total
flat flat% sum% cum cum%
Demo
package main
import (
"net/http"
_ "net/http/pprof"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
runtime.SetMutexProfileFraction(1)
runtime.SetBlockProfileRate(1)
go func() {
http.ListenAndServe(":6060", nil)
}()
for {
stupidMutexUse()
}
}
func stupidMutexUse() {
m := &sync.Mutex{}
m.Lock()
go func() {
time.Sleep(time.Second)
m.Unlock()
}()
m.Lock()
}
可以看到,这个锁由主协程 Lock,并启动子协程去 Unlock,主协程会阻塞在第二次 Lock 这儿(等待1秒,直到子协程完成任务)。
因此,由于子协程足足睡眠了一秒,导致主协程等待这个锁的释放足足等了一秒钟。
在实际的业务代码中,我们使用 Mutex 很正常,但是如果监测到了类似这种主协程被长期阻塞的情况,就要考虑如果优化子协程中代码的实现了。
$ go tool pprof http://localhost:6060/debug/pprof/mutex
Fetching profile over HTTP from http://localhost:6060/debug/pprof/mutex
Saved profile in /Users/weishi/pprof/pprof.contentions.delay.011.pb.gz
Type: delay
Time: Aug 22, 2020 at 1:11pm (+08)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 8.02s, 100% of 8.02s total
flat flat% sum% cum cum%
8.02s 100% 100% 8.02s 100% sync.(*Mutex).Unlock
0 0% 100% 8.02s 100% main.stupidMutexUse.func1
(pprof) list stupid
Total: 8.02s
ROUTINE ======================== main.stupidMutexUse.func1 in /Users/weishi/Working/GoPlayground/sw_pprof/sw_pprof.go
0 8.02s (flat, cum) 100% of Total
. . 26:func stupidMutexUse() {
. . 27: m := &sync.Mutex{}
. . 28: m.Lock()
. . 29: go func() {
. . 30: time.Sleep(time.Second)
. 8.02s 31: m.Unlock()
. . 32: }()
. . 33: m.Lock()
. . 34:}
Reference
- https://github.com/google/pprof/blob/master/doc/README.md
- https://golang.org/doc/diagnostics.html
- https://golang.org/pkg/net/http/pprof/
- https://blog.golang.org/pprof
- https://golang.org/pkg/runtime/pprof/