goroutine 并发案例
2023-02-01 19:57 糯米粥 阅读(40) 评论(0) 编辑 收藏 举报
1. go select是一种仅能用于channel发送和接收消息的语句,此语句运行期间是阻塞的;当 select中没有case语句的时候,会阻塞当前goroutine
2. select是go在语言层面提供的IO多路复用机制,专门用于检测多个channel是否准备完毕:可读可写
3. select语句中除default外,每个case操作一个channel,要么读要么写
4. select语句中除default外,各case的执行顺序是完全随机的
5. select中如果没有default语句,则会阻塞等待任一case
6. select语句中读操作要判断是否成功读取,关闭的channel也可以读取
package main import ( "fmt" "time" ) type document struct { source string name string address string mobile string } // 采集A数据 func readA() chan document { c := make(chan document) go func() { i := 0 for { //模拟等待3s time.Sleep(3 * time.Second) c <- document{ source: "A", name: fmt.Sprintf("姓名%d", i), //模拟数据 address: fmt.Sprintf("地址%d", i), mobile: fmt.Sprintf("手机号码%d", i), } i++ } }() return c } // 采集B数据 func readB() chan document { c := make(chan document) go func() { i := 0 for { //模拟等待1s,2边的时间不能等待一样 time.Sleep(1 * time.Second) c <- document{ source: "B", name: fmt.Sprintf("姓名%d", i), //模拟数据 address: fmt.Sprintf("地址%d", i), mobile: fmt.Sprintf("手机号码%d", i), } i++ } }() return c } // 分别从每个采集中接收数据,分发到main func receiveInfo(chs ...chan document) chan document { doc := make(chan document) for _, c := range chs { go func(in chan document) { for { doc <- <-in //从c中接收消息,发送给c } }(c) } return doc } // func main() { // ch1 := make(chan<- int, 1) // ch2 := make(chan int, 1) // ch1 <- 9 // select { // case ch1 <- 90: // fmt.Println("ch1 pop one element") // case <-ch2: // fmt.Println("ch2 pop one element") // } // } func main() { //接收数据,模拟入库 a := readA() //创建A b := readB() //创建b receA := receiveInfo(a, b) for { /*fmt.Println(<-c1) fmt.Println(<-c2)*/ //m := <-receA //if m.source == "A" { // time.Sleep(5 * time.Second) // //如果这里逻辑处理比较慢,处理速度大于传来的速度,数据就会丢失 // fmt.Printf("接收A的数据,并入库:%s\n", m) //} else { // fmt.Printf("接收B的数据,并入库:%s\n", m) //} //如果这里逻辑处理比较慢,处理速度大于传来的速度,数据就会丢失,所以先保存数据 var values []document select { case n := <-receA: values = append(values, n) } if len(values) > 0 { m := values[0] //获取第一个 if m.source == "A" { time.Sleep(5 * time.Second) fmt.Printf("接收A的数据,并入库:%+v\n", m) } else { fmt.Printf("接收B的数据,并入库:%+v\n", m) } //删除第一个 values = values[1:] } //select { //case m.source == "A": // fmt.Printf("接收A的数据,并入库:%s\n", m) // case m.source=="B" // fmt.Printf("接收A的数据,并入库:%s\n", m) //} } }
参考:
https://www.cnblogs.com/xingchong/p/15826630.html
https://www.cnblogs.com/juanmaofeifei/p/14436952.html