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-11-12Cargo deny安装指路
- 2024-11-02MongoDB项目实战:从入门到初级应用
- 2024-11-01随时随地一键转录,Google Cloud 新模型 Chirp 2 让语音识别更上一层楼
- 2024-10-25Google Cloud动手实验详解:如何在Cloud Run上开发无服务器应用
- 2024-10-24AI ?先驱齐聚 BAAI 2024,发布大规模语言、多模态、具身、生物计算以及 FlagOpen 2.0 等 AI 模型创新成果。
- 2024-10-20goland工具下,如修改一个项目的标准库SDK的版本-icode9专业技术文章分享
- 2024-10-17Go学习:初学者的简单教程
- 2024-10-17Go学习:新手入门完全指南
- 2024-10-17Golang学习:初学者入门教程
- 2024-10-17Golang学习:新手入门教程