Files
bulma/handoff_trigger.go

154 lines
3.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"fmt"
"net/http"
"os/exec"
"runtime"
"sync"
"time"
)
// 验证Hand Off触发场景,覆盖所有核心触发类型
func main() {
// 限制P数量为1,放大Hand Off效果(若不触发,G2需等待G1完成)
runtime.GOMAXPROCS(1)
fmt.Printf("当前P的数量: %d\n", runtime.GOMAXPROCS(0))
// 强制GC和调度器初始化
runtime.GC()
time.Sleep(10 * time.Millisecond)
// 1. 阻塞式网络I/O触发Hand Off
testBlockNetIO()
fmt.Println("=== 分割线 ===")
// 2. time.Sleep()触发Hand Off
testTimeSleep()
fmt.Println("=== 分割线 ===")
// 3. os/exec执行外部命令触发Hand Off
testExecCommand()
}
// 场景1:阻塞式网络I/O(HTTP请求)
func testBlockNetIO() {
var wg sync.WaitGroup
// 控制执行顺序,避免调度随机性
g1Start := make(chan struct{})
g2Exec := make(chan struct{})
// G1:执行阻塞式HTTP请求
wg.Add(1)
go func() {
defer wg.Done()
close(g1Start)
fmt.Println("G1: 开始执行阻塞式HTTP请求")
// 阻塞式网络I/O
_, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Printf("G1: HTTP请求异常: %v\n", err)
}
fmt.Println("G1: HTTP请求完成")
close(g2Exec)
}()
// 等待G1启动后,启动G2
<-g1Start
time.Sleep(50 * time.Millisecond)
// G2:验证Hand Off生效(若触发则立即执行)
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("G2: 开始执行(验证网络I/O触发Hand Off")
<-g2Exec
fmt.Println("G2: 执行完成")
}()
wg.Wait()
}
// 场景2time.Sleep()触发Hand Off
func testTimeSleep() {
var wg sync.WaitGroup
g1Sleep := make(chan struct{})
// G1:执行time.Sleep()
wg.Add(1)
go func() {
defer wg.Done()
close(g1Sleep)
fmt.Println("G1: 开始执行time.Sleep(1秒)")
time.Sleep(1 * time.Second)
fmt.Println("G1: sleep完成,恢复执行")
}()
// 等待G1进入sleep后,启动G2
<-g1Sleep
time.Sleep(50 * time.Millisecond)
// G2:验证Hand Off生效
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("G2: 开始执行(验证time.Sleep触发Hand Off")
}()
wg.Wait()
}
// 场景3os/exec执行外部命令
func testExecCommand() {
var wg sync.WaitGroup
g1Exec := make(chan struct{})
g2Started := make(chan struct{})
// G1:执行外部sleep命令
wg.Add(1)
go func() {
defer wg.Done()
close(g1Exec) // 通知G1已启动
fmt.Println("G1: 执行外部命令 sleep 1s")
// 关键:在阻塞前让出处理器,确保调度器有机会切换
runtime.Gosched()
// 跨平台命令执行
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
fmt.Println("检测到Windows系统,使用timeout命令")
cmd = exec.Command("powershell", "-command", "Start-Sleep -Seconds 1")
} else {
cmd = exec.Command("sleep", "1")
}
err := cmd.Run()
if err != nil {
fmt.Printf("G1: 命令执行错误: %v\n", err)
}
fmt.Println("G1: 外部命令执行完成")
}()
// 等待G1启动
<-g1Exec
time.Sleep(10 * time.Millisecond) // 短暂等待确保G1进入阻塞
// G2:验证Hand Off生效
wg.Add(1)
go func() {
defer wg.Done()
close(g2Started)
fmt.Println("G2: 开始执行(验证os/exec触发Hand Off")
}()
// 等待G2启动确认
select {
case <-g2Started:
fmt.Println("验证成功: G2在G1阻塞期间执行")
case <-time.After(500 * time.Millisecond):
fmt.Println("警告: G2未及时执行,可能未触发Hand Off")
}
wg.Wait()
}