111 lines
3.3 KiB
Go
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 任务占比不足,可重启程序重试。")
|
|
}
|
|
}
|