160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
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()
|
||
}
|