代码改变世界

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)
        //}
    }
}
View Code

 

 

参考:

https://www.cnblogs.com/xingchong/p/15826630.html

https://www.cnblogs.com/juanmaofeifei/p/14436952.html