76 lines
1.6 KiB
Go
76 lines
1.6 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"runtime"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// 验证系统调用阻塞触发Hand Off
|
||
func testSyscallHandoff() {
|
||
runtime.GOMAXPROCS(1) // 限制P的数量为1,放大Hand Off效果
|
||
var wg sync.WaitGroup
|
||
readyCh := make(chan struct{})
|
||
|
||
// 启动G1:执行阻塞式系统调用
|
||
wg.Add(1)
|
||
go func() {
|
||
defer wg.Done()
|
||
|
||
// 创建管道用于阻塞读取
|
||
r, w, err := os.Pipe()
|
||
if err != nil {
|
||
fmt.Printf("创建管道失败: %v\n", err)
|
||
return
|
||
}
|
||
defer r.Close()
|
||
defer w.Close()
|
||
|
||
fmt.Println("G1: 执行阻塞系统调用(sleep 2s)")
|
||
close(readyCh) // 通知主goroutine G1已准备好阻塞
|
||
|
||
// 创建缓冲区
|
||
buf := make([]byte, 1)
|
||
|
||
// 在后台goroutine中2秒后写入数据解除阻塞
|
||
go func() {
|
||
time.Sleep(2 * time.Second)
|
||
w.Write([]byte{1}) // 写入一个字节解除读取阻塞
|
||
}()
|
||
|
||
// 执行阻塞读取(真正的系统调用阻塞)
|
||
_, _ = r.Read(buf)
|
||
fmt.Println("G1: 系统调用完成,恢复执行")
|
||
}()
|
||
|
||
// 等待G1准备好阻塞
|
||
<-readyCh
|
||
|
||
// 短暂延迟,确保G1已进入阻塞状态
|
||
time.Sleep(50 * time.Millisecond)
|
||
|
||
// 启动G2:验证Hand Off后P可调度新G
|
||
wg.Add(1)
|
||
go func() {
|
||
defer wg.Done()
|
||
fmt.Println("G2: 开始执行(验证Hand Off生效)")
|
||
for i := 0; i < 5; i++ {
|
||
fmt.Printf("G2: 执行中... %d\n", i)
|
||
time.Sleep(300 * time.Millisecond)
|
||
}
|
||
fmt.Println("G2: 执行完成")
|
||
}()
|
||
|
||
wg.Wait()
|
||
fmt.Println("所有G执行完成,验证结束")
|
||
}
|
||
|
||
func main() {
|
||
// 先设置GOMAXPROCS,再获取
|
||
runtime.GOMAXPROCS(1)
|
||
fmt.Printf("当前P的数量: %d\n", runtime.GOMAXPROCS(0))
|
||
testSyscallHandoff()
|
||
}
|