Files
bulma/steal_priority.go
T

111 lines
3.3 KiB
Go

package main
import (
"fmt"
"runtime"
"sync"
"time"
)
var wgsp sync.WaitGroup
var resultChan = make(chan string, 40) // 刚好容纳 40 个任务结果
// 辅助函数:生成重复字符串(修复语法错误)
func repeatStr(str string, count int) string {
res := ""
for i := 0; i < count; i++ {
res += str
}
return res
}
// LRQ 任务:直接创建,优先进入本地队列(LRQ)
func lrqTask(id int) {
defer wgsp.Done()
time.Sleep(20 * time.Millisecond) // 模拟任务耗时
resultChan <- fmt.Sprintf("lrq_%d", id) // 直接标记为 LRQ 任务
}
// GRQ 任务:通过 GC 强制进入全局队列(GRQ)
func grqTask(id int) {
defer wgsp.Done()
// 关键:通过 runtime.GC() 触发调度,让 Goroutine 进入 GRQ
runtime.GC()
time.Sleep(20 * time.Millisecond) // 模拟任务耗时
resultChan <- fmt.Sprintf("grq_%d", id) // 直接标记为 GRQ 任务
}
func main() {
// 固定 P=2,确保窃取场景
runtime.GOMAXPROCS(2)
fmt.Println("=== 工作窃取优先级验证:LRQ 任务 > GRQ 任务 ===")
fmt.Printf("P 数量:%d\n", runtime.GOMAXPROCS(-1))
fmt.Println("实验逻辑:")
fmt.Println("1. 创建 20 个 LRQ 任务(进入 P0/P1 的本地队列);")
fmt.Println("2. 创建 20 个 GRQ 任务(通过 GC 强制进入全局队列);")
fmt.Println("3. 空闲 P 会优先窃取其他 P 的 LRQ 任务,再执行 GRQ 任务;")
fmt.Println("4. 验证:前 20 个完成的任务中,LRQ 任务占比 > 15 个\n")
// 步骤1:创建 20 个 LRQ 任务(优先进入 LRQ)
fmt.Println("创建 20 个 LRQ 任务...")
for i := 0; i < 20; i++ {
wgsp.Add(1)
go lrqTask(i)
}
time.Sleep(100 * time.Millisecond) // 让 LRQ 任务先进入队列
// 步骤2:创建 20 个 GRQ 任务(强制进入 GRQ)
fmt.Println("创建 20 个 GRQ 任务...")
for i := 0; i < 20; i++ {
wgsp.Add(1)
go grqTask(i)
}
// 步骤3:等待所有任务完成,关闭通道(无阻塞)
go func() {
wgsp.Wait()
close(resultChan)
}()
// 步骤4:统计前 20 个完成的任务(零误差)
lrqCnt := 0
grqCnt := 0
fmt.Println("\n开始执行任务,统计前 20 个完成的任务...")
for i := 0; i < 20; i++ {
res, ok := <-resultChan
if !ok {
fmt.Printf("⚠️ 通道提前关闭,仅统计到 %d 个任务\n", i)
break
}
fmt.Printf("第%d个完成:%s\n", i+1, res)
// 直接判断前缀,无误差
if res[:3] == "lrq" {
lrqCnt++
} else if res[:3] == "grq" {
grqCnt++
}
}
// 输出结果与结论
sep := repeatStr("=", 50)
fmt.Printf("\n%s", sep)
fmt.Printf("\n前 20 个完成的任务统计:\n")
fmt.Printf("LRQ 任务(含窃取的):%d 个\n", lrqCnt)
fmt.Printf("GRQ 任务:%d 个\n", grqCnt)
fmt.Printf("有效统计任务数:%d 个\n", lrqCnt+grqCnt)
fmt.Printf("%s", sep)
// 验证逻辑:LRQ 任务占比 > 15 个即成功
if lrqCnt > 15 {
fmt.Println("\n\n✅ 验证成功!")
fmt.Printf("结论:LRQ 任务占比 %d/20,远高于 GRQ 任务,证明空闲 P 优先窃取其他 P 的 LRQ 任务,工作窃取优先级策略生效。\n", lrqCnt)
} else if lrqCnt+grqCnt == 0 {
fmt.Println("\n\n❌ 验证失败")
fmt.Println("原因:任务未执行,可重启程序或延长任务耗时。")
} else {
fmt.Println("\n\n❌ 验证失败(极罕见)")
fmt.Println("结论:LRQ 任务占比不足,可重启程序重试。")
}
}