Files
bulma/handoff_notrigger.go

160 lines
3.8 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"
"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: 计算完成,耗时%vsum=%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()
}