前言

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

1.使用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)        //输出消费数量
}

3. groupWait的使用:

var wg sync.WaitGroup    //定义
wg.Add(10)   //设置数值为10
wg.Done()    //数值减1
wg.Wait()    //为0时线程继续往下执行

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

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