goroutine和chan
2022/3/9 6:14:55
本文主要是介绍goroutine和chan,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
package main import ( "errors" "fmt" "reflect" "sync" "syscall" "unsafe" ) var wg sync.WaitGroup var once sync.Once type Str struct { num int pid int } type hchan struct { qcount uint // total data in the queue dataqsiz uint // size of the circular queue buf unsafe.Pointer // points to an array of dataqsiz elements elemsize uint16 closed uint32 } type ChanInfo struct { Closed bool // 是否关闭 Len uint // channel内数据量 Cap uint // channel容量 Block bool // 是否已经阻塞 } func ChanStatus(c interface{}) (*ChanInfo, error) { v := reflect.ValueOf(c) if v.Type().Kind() != reflect.Chan { return nil, errors.New("type must be channel") } i := (*[2]uintptr)(unsafe.Pointer(&c)) h := (*hchan)(unsafe.Pointer(i[1])) return &ChanInfo{ Cap: h.dataqsiz, Len: h.qcount, Closed: h.closed == 1, Block: h.qcount >= h.dataqsiz, }, nil } func GetCurrentThreadId() int { var user32 *syscall.DLL var GetCurrentThreadId *syscall.Proc var err error user32, err = syscall.LoadDLL("Kernel32.dll") if err != nil { fmt.Printf("syscall.LoadDLL fail: %v\n", err.Error()) return 0 } GetCurrentThreadId, err = user32.FindProc("GetCurrentThreadId") if err != nil { fmt.Printf("user32.FindProc fail: %v\n", err.Error()) return 0 } var pid uintptr pid, _, err = GetCurrentThreadId.Call() return int(pid) } func f1(ch1 chan int) { defer wg.Done() for i := 0; i < 98; i++ { ch1 <- i } ch1 <- 666 ch1 <- 666 close(ch1) } func f2(ch1 chan int, ch2 chan Str) { defer wg.Done() for { //ChanInfo, _ := ChanStatus(ch1) x, ok := <-ch1 if x == 666 && ok == true { break } var s Str s.num = x s.pid = GetCurrentThreadId() //if ChanInfo.Closed { ch2 <- s //} } } func f3(ch1 chan int, ch2 chan Str) { defer wg.Done() for { x, ok := <-ch1 if !ok { break } var s Str s.num = x s.pid = GetCurrentThreadId() ch2 <- s //可能是运行到这 } // close(ch2) once.Do(func() { close(ch2) }) } func main() { ch1 := make(chan int, 100) ch2 := make(chan Str, 100) // ch3 := make(chan Str, 100) wg.Add(3) go f1(ch1) go f2(ch1, ch2) go f2(ch1, ch2) wg.Wait() close(ch2) for { x, ok := <-ch2 if !ok { break } fmt.Println(x.num, x.pid) } // 直接判断状态会有问题,就是运行的时候可能是这个函数先运行了,第一次就直接ok==false跳出了 //于是我拿到了chan的结构信息,想通过长度或者close的状态是否关闭来判断,就又会有可能出现在同一个索引上取值,或者第一个运行到关闭那了,第二个运行到赋值那了 //因为两个结束标记是666 ,第一个线程判断第一个666为真就跳出去执行了,但是第二个线程要么拿到第二个666然后跳出,要么跟第一个同时拿到,因为值被第一个拿了, //第二个就拿了个空,还继续去赋值,还在赋值的时候,第一个又还没执行到close的可能,就panic: send on closed channel //close要在外部关闭, 关闭后不能继续赋值 }
这篇关于goroutine和chan的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24MongoDB资料:新手入门完全指南
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享