Go踩坑笔记01-生产者消费者模型

前言

创建生产者消费者模型,首先必须要了解到Go有个天然的并发队列channel,Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯,简单来说就是channel可以在协程之间传递数据,协程就是类似Java的多线程。用channel来传递"产品", 不再需要自己去加锁维护一个全局的阻塞队列。

1.使用go标识符创建协程:

  • 在方法调用或者代码块前面加上go关键词即可
go test()   //第一种
go func(){   代码块   }()  //第二种

2.代码实现:

  • 首先创建一个生产者:
// chan<-表示此通道只能写    生产者
func produce( p chan<- int64, produceNum int) {
    for i := 0; i < produceNum; i++ {  
        timeUnix := time.Now().UnixNano()    //获取时间戳,单位毫秒
        temp := timeUnix + int64(i)
        p <- temp  //将时间戳写入p 
        fmt.Println("send:", temp)
    }
}

  • 创建一个消费者:
// <-chan表示此通道只能读   消费者
func consumer(c <-chan int64, id int, count int, wg *sync.WaitGroup) { 
    for v := range c {      //读取管道,直到关闭管道为止,没有值,那么阻塞
        fmt.Printf("消费者%d, receive: %d\n",id, v)
        count++       
        wg.Done()           //消费一次减1
    }
}
  • 主协程里调用方法:
func main() {
    ch := make(chan int64)  //创建channel,类型为int64
    var wg sync.WaitGroup   //线程控制
    var count = 0           //统计消费数量
    var produceNum = 10     //生产数量
    var idNum = 5           //消费者数量
    wg.Add(produceNum)      //数值设置为生产的数量
    
    
    for i := 1; i<=idNum; i++ {
        go consumer(ch, i, count, &wg)  //调用消费者
    }
    go produce(ch, produceNum)          //调用生产者

    wg.Wait()
    fmt.Println("消费了:",count)        //输出消费数量
}
  • 输出结果:
    Go踩坑笔记01-生产者消费者模型_第1张图片

3.groupWait的使用:

  • 没有使用groupWait之前,是使用**time.Sleep(time.Second)**来睡眠主协程来等待子协程的返回。
  • 使用groupWait的方法很简单
var wg sync.WaitGroup    //定义
wg.Add(10)   //设置数值为10
wg.Done()    //数值减1
wg.Wait()    //为0时线程继续往下执行
  • 这样就可以将主线程卡在wg.Wait()这一行代码,当wg.Done()将wg.Wait()的值减为0时候,线程才可以继续往下执行。

4.使用结构体创建生产者消费者模型遇到的坑:

  • 首先就是变量、方法的名称大写表示public,其他类才能引用到;小写则表示private
  • 引用时候没加go标识符开启子协程,导致主线程自己去执行生产者或者消费者方法后,管道里只有生产者或者只有消费者,协程在等待一个永远不会到来的数据,造成死锁。

你可能感兴趣的:(GO踩坑笔记)