package main import ( "fmt" "net" "runtime" "sync" "syscall" "time" ) // 验证Hand Off非触发场景,覆盖所有核心非触发类型 func main() { // 限制P数量为1,关闭异步抢占后,G2必须等待G1完成 runtime.GOMAXPROCS(1) fmt.Printf("当前P的数量: %d\n", runtime.GOMAXPROCS(0)) // 1. 纯CPU密集型计算(非触发) testCPUCompute() fmt.Println("=== 分割线 ===") // 2. 带缓冲Channel(非满)(非触发) testBufferedChan() fmt.Println("=== 分割线 ===") // 3. 非阻塞网络操作(非触发) testNonblockNet() } // 场景1:纯CPU密集型计算(核心强化:避免调度器抢占干扰) func testCPUCompute() { var wg sync.WaitGroup // 用于确认G1完全执行完毕后,G2才打印 g1Done := make(chan struct{}) // G1:1亿次累加(纯CPU计算,无阻塞) wg.Add(1) go func() { defer wg.Done() fmt.Println("G1: 开始纯CPU计算(10亿次累加)") start := time.Now() var sum int64 = 0 // 密集计算,确保长时间占据P for i := 0; i < 100000000; i++ { sum += int64(i) // 禁止调度器抢占(仅用于验证,生产环境不建议) runtime.LockOSThread() defer runtime.UnlockOSThread() } fmt.Printf("G1: 计算完成,耗时%v,sum=%d\n", time.Since(start), sum) close(g1Done) }() // G2:必须等待G1完成后才能执行(验证无Hand Off) wg.Add(1) go func() { defer wg.Done() // 阻塞直到G1完成 <-g1Done fmt.Println("G2: 尝试执行(无Hand Off则等待G1完成)") }() wg.Wait() } // 场景2:带缓冲Channel(非满)(非触发) func testBufferedChan() { var wg sync.WaitGroup ch := make(chan int, 2) g1Done := make(chan struct{}) // G1:向未满的Channel发送数据(无阻塞) wg.Add(1) go func() { defer wg.Done() fmt.Println("G1: 向带缓冲Channel发送数据(非满)") ch <- 1 ch <- 2 // 模拟耗时操作,确保占据P time.Sleep(500 * time.Millisecond) fmt.Println("G1: 数据发送完成") close(g1Done) }() // G2:必须等待G1完成后才能执行 wg.Add(1) go func() { defer wg.Done() <-g1Done fmt.Println("G2: 尝试执行(无Hand Off则等待G1)") val := <-ch fmt.Printf("G2: 接收数据%d\n", val) }() wg.Wait() close(ch) } // 场景3:非阻塞网络操作(非触发)- 修正SetNonblock调用方式 func testNonblockNet() { var wg sync.WaitGroup g1Done := make(chan struct{}) // 先拨号建立连接 conn, err := net.Dial("tcp", "www.baidu.com:80") if err != nil { fmt.Printf("创建连接异常: %v\n", err) return } defer conn.Close() // 转换为TCPConn并获取底层文件描述符,设置非阻塞模式 tcpConn, ok := conn.(*net.TCPConn) if !ok { fmt.Println("转换为TCPConn失败") return } file, err := tcpConn.File() if err != nil { fmt.Printf("获取文件描述符失败: %v\n", err) return } defer file.Close() // 设置非阻塞模式 if err := syscall.SetNonblock(syscall.Handle(int(file.Fd())), true); err != nil { fmt.Printf("设置非阻塞失败: %v\n", err) return } // G1:非阻塞写数据(无OS级阻塞) wg.Add(1) go func() { defer wg.Done() fmt.Println("G1: 非阻塞写入网络数据") _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n")) if err != nil { if opErr, ok := err.(*net.OpError); ok && opErr.Temporary() { fmt.Println("G1: 非阻塞写入暂时不可用(正常非阻塞行为)") } else { fmt.Printf("G1: 非阻塞写入异常: %v\n", err) } } // 模拟耗时操作,占据P time.Sleep(500 * time.Millisecond) fmt.Println("G1: 非阻塞写入完成") close(g1Done) }() // G2:必须等待G1完成后才能执行 wg.Add(1) go func() { defer wg.Done() <-g1Done fmt.Println("G2: 尝试执行(无Hand Off则等待G1完成)") }() wg.Wait() }