可视化 GMP 编程
有 2 种方式可以查看一个程序的 GMP 的数据。
方式 1:go tool trace
trace 记录了运行时的信息,能提供可视化的 Web 页面。
简单测试代码:main 函数创建 trace,trace 会运行在单独的 goroutine 中,然后 main 打印”Hello World” 退出。
trace.go
package main import ( "os" "fmt" "runtime/trace" ) func main() { //创建trace文件 f, err := os.Create("trace.out") if err != nil { panic(err) } defer f.Close() //启动trace goroutine err = trace.Start(f) if err != nil { panic(err) } defer trace.Stop() //main fmt.Println("Hello World") }
运行程序
$ go run trace.go Hello World
会得到一个 trace.out 文件,然后我们可以用一个工具打开,来分析这个文件。
2021/01/05 16:38:01 Parsing trace... 2021/01/05 16:38:01 Splitting trace... 2021/01/05 16:38:01 Opening browser. Trace viewer is listening on http://127.0.0.1:58040
我们可以通过浏览器打开 http://127.0.0.1:58040/ 网址,点击 view trace 能够看见可视化的调度流程。
G 信息
点击 Goroutines 那一行可视化的数据条,我们会看到一些详细的信息。
一共有两个G在程序中,一个是特殊的G0,是每个M必须有的一个初始化的G,这个我们不必讨论。
其中 G1 应该就是 main goroutine (执行 main 函数的协程),在一段时间内处于可运行和运行的状态。
M 信息
点击 Threads 那一行可视化的数据条,我们会看到一些详细的信息。
一共有两个 M 在程序中,一个是特殊的 M0,用于初始化使用,这个我们不必讨论。
P 信息
G1 中调用了 main.main,创建了 trace goroutine g6。G1 运行在 P0 上,G6运行在 P1 上。
这里有两个 P,我们知道,一个 P 必须绑定一个 M 才能调度 G。
我们在来看看上面的 M 信息。
我们会发现,确实 G6 在 P1 上被运行的时候,确实在 Threads 行多了一个 M 的数据,点击查看如下:
多了一个 M2 应该就是 P1 为了执行 G6 而动态创建的 M2.
方式 2:Debug trace
package main import ( "fmt" "time" ) func main() { for i := 0; i < 5; i++ { time.Sleep(time.Second) fmt.Println("Hello World") } }
编译
$ go build trace2.go
通过 Debug 方式运行
$ GODEBUG=schedtrace=1000 ./trace2 SCHED 0ms: gomaxprocs=2 idleprocs=0 threads=4 spinningthreads=1 idlethreads=1 runqueue=0 [0 0] Hello World SCHED 1003ms: gomaxprocs=2 idleprocs=2 threads=4 spinningthreads=0 idlethreads=2 runqueue=0 [0 0] Hello World SCHED 2014ms: gomaxprocs=2 idleprocs=2 threads=4 spinningthreads=0 idlethreads=2 runqueue=0 [0 0] Hello World SCHED 3015ms: gomaxprocs=2 idleprocs=2 threads=4 spinningthreads=0 idlethreads=2 runqueue=0 [0 0] Hello World SCHED 4023ms: gomaxprocs=2 idleprocs=2 threads=4 spinningthreads=0 idlethreads=2 runqueue=0 [0 0] Hello World
SCHED
:调试信息输出标志字符串,代表本行是 goroutine 调度器的输出;
0ms
:即从程序启动到输出这行日志的时间;
gomaxprocs
: P 的数量,本例有 2 个 P, 因为默认的 P 的属性是和 cpu 核心数量默认一致,当然也可以通过 GOMAXPROCS 来设置;
idleprocs
: 处于 idle 状态的 P 的数量;通过 gomaxprocs 和 idleprocs 的差值,我们就可知道执行 go 代码的 P 的数量;
threads
: os threads/M 的数量,包含 scheduler 使用的 m 数量,加上 runtime 自用的类似 sysmon 这样的 thread 的数量;
spinningthreads
: 处于自旋状态的 os thread 数量;
idlethread
: 处于 idle 状态的 os thread 的数量;
runqueue=0
: Scheduler 全局队列中 G 的数量;
[0 0]
: 分别为 2 个 P 的 local queue 中的 G 的数量。
- 本文固定链接: https://phpmianshi.com/?id=390
- 转载请注明: admin 于 PHP面试网 发表
《本文》有 0 条评论