【Golang 面试题】每日 3 题(五十八)
✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/UWz06
📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
172. 信号的抢占式调度如何实现?
下面是一个简单的基于信号的抢占式调度的示例代码:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
go func() {
for {
fmt.Println("Goroutine 1 is running")
runtime.Gosched()
}
}()
go func() {
for {
fmt.Println("Goroutine 2 is running")
runtime.Gosched()
}
}()
for {
fmt.Println("Main Goroutine is running")
time.Sleep(time.Second)
}
}
在这个示例代码中,我们定义了三个 Goroutine,分别是“Goroutine 1”、“Goroutine 2”和“Main Goroutine”。其中,“Goroutine 1”和“Goroutine 2”分别不断输出自己的名称,并在每次输出后使用 runtime.Gosched() 函数让出 CPU 时间片,从而实现抢占式调度。而“Main Goroutine”每秒输出一次自己的名称,并使用 time.Sleep() 函数暂停一秒钟,从而实现协作式调度。
需要注意的是,基于信号的抢占式调度不适用于所有场景,因为频繁调用 runtime.Gosched() 函数会导致性能下降,应该根据实际需求进行选择。
173. go tool trace 如何启动?
启动可视化界面:
go run trace.go
go tool trace trace.out
2022/04/22 10:44:11 Parsing trace...
2022/04/22 10:44:11 Splitting trace...
2022/04/22 10:44:11 Opening browser. Trace viewer is listening on http://127.0.0.1:35488
打开 http://127.0.0.1:35488 查看可视化界面:
点击 view trace 能够看见可视化的调度流程:
174. 怎么使用 go tool trace 查看运行时的调度信息?
trace.go
package main
import (
"fmt"
"os"
"runtime/trace"
"time"
)
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
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
fmt.Println("Hello World")
}
}
一共有 2 个 G 在程序中,一个是特殊的 G0,是每个 M 必须有的一个初始化的 G,另外一个是 G1 main goroutine (执行 main 函数的协程),在一段时间内处于可运行和运行的状态。
- 点击 Threads 那一行可视化的数据条,我们会看到 M 详细的信息
一共有 2 个 M 在程序中,一个是特殊的 M0,用于初始化使用,另外一个是用于执行 G1 的 M1。
- 点击 Proc 那一行可视化的数据条,我们会看到 P 上正在运行 goroutine 详细的信息
一共有 3 个 P 在程序中,分别是 P0、P1、P2。
点击具体的 Goroutine 行为后可以看到其相关联的详细信息:
Start:开始时间
Wall Duration:持续时间
Self Time:执行时间
Start Stack Trace:开始时的堆栈信息
End Stack Trace:结束时的堆栈信息
Incoming flow:输入流
Outgoing flow:输出流
Preceding events:之前的事件
Following events:之后的事件
All connected:所有连接的事件