前言
创建生产者消费者模型,首先必须要了解到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标识符开启子协程,导致主线程自己去执行生产者或者消费者方法后,管道里只有生产者或者只有消费者,协程在等待一个永远不会到来的数据,造成死锁。