生产者与消费者模式
概述
生产者消费者问题是经典的并发同步问题。描述有若干生产者和若干消费者,生产者负责生产产品并将产品放入盒子(缓冲区),而消费者则消费盒子的产品。问题的关键为消费者之间、生产者之间、消费者与生产者之间的竞争,以及在“盒子”满了,应该停止(阻塞)生产者的生产,在“盒子”空了应该停止(阻塞)消费者的消费。传统的方式,我们需要用锁,信号量等来处理,而Go并不需要,通过Go的goroutine以及channel可以很方便的实现生产者消费者模型。
生产者与消费者,可以一对多,也可以多对一,也可以多对多,本节以最复杂情况多对多为例展开分析。
示例代码:
package main
import "fmt"
func Producer(id int, ch chan int, done chan bool) {
for i := 1; i <= 10; i++ {
fmt.Printf("%v号生产者,产生数据: %v \n", id, i)
ch <- i
}
done <- true
//在开启多个goroutine进行生产时,不能在函数内部将通道关闭。
//此处往done通道内写数据,目的为了表示子goroutine生产完毕
//当在主函数中能把取出相应数量(numProduc)的元素时,即代表所有生产结束,通道可关闭
}
func Consumer(id int, ch chan int, done chan bool) {
for v := range ch {
fmt.Printf("%v号消费者,消费数据:%v \n", id, v)
}
done <- true
//函数主体结束时,往通道里写一个数据。
//当开启多个goroutine时,每个协程结束都往通道写一个数据,相当于告诉外界,我消费结束了。
//在主函数末尾,依次取出该通道内数据,能当全部取出,就代表所有子goroutine结束,主程序也可退出。
//相当于起到同步等待的作用
}
func main() {
ch := make(chan int, 20)
numProduc := 3 //以三个生产者为例
numConsum := 5 //以五个消费者为例
donePr := make(chan bool, numProduc) //donePr的容量即为生产者数量
doneCo := make(chan bool, numConsum) //doneCo的容量即为消费者数量
for i := 1; i <= numProduc; i++ {
go Producer(i, ch, donePr)
}
for j := 1; j <= numConsum; j++ {
go Consumer(j, ch, doneCo)
}
for ii := 0; ii < numProduc; ii++ {
<-donePr //done通道内的数据可全部写出,代表所有生产结束,ch通道可关闭
}
close(ch)
for jj := 0; jj < numConsum; jj++ {
<-doneCo //把done通道内的数据写出,起到一个wait()的作用,等待子进程全部结束,之后主进程便可结束
}
}
输出结果:
1号生产者,产生数据: 1
1号生产者,产生数据: 2
1号生产者,产生数据: 3
1号生产者,产生数据: 4
1号生产者,产生数据: 5
1号生产者,产生数据: 6
1号生产者,产生数据: 7
1号生产者,产生数据: 8
1号生产者,产生数据: 9
1号生产者,产生数据: 10
3号生产者,产生数据: 1
2号消费者,消费数据:3
2号消费者,消费数据:6
3号生产者,产生数据: 2
5号消费者,消费数据:1
3号生产者,产生数据: 3
5号消费者,消费数据:8
3号生产者,产生数据: 4
3号消费者,消费数据:4
3号消费者,消费数据:10
3号消费者,消费数据:1
3号消费者,消费数据:2
3号消费者,消费数据:3
3号消费者,消费数据:4
4号消费者,消费数据:5
3号生产者,产生数据: 5
3号生产者,产生数据: 6
3号生产者,产生数据: 7
3号生产者,产生数据: 8
3号生产者,产生数据: 9
3号生产者,产生数据: 10
2号生产者,产生数据: 1
2号生产者,产生数据: 2
2号生产者,产生数据: 3
2号生产者,产生数据: 4
2号消费者,消费数据:7
2号消费者,消费数据:7
2号消费者,消费数据:8
3号消费者,消费数据:5
3号消费者,消费数据:10
3号消费者,消费数据:1
3号消费者,消费数据:2
3号消费者,消费数据:3
3号消费者,消费数据:4
2号生产者,产生数据: 5
2号生产者,产生数据: 6
2号生产者,产生数据: 7
2号生产者,产生数据: 8
2号生产者,产生数据: 9
1号消费者,消费数据:2
1号消费者,消费数据:6
1号消费者,消费数据:7
4号消费者,消费数据:6
4号消费者,消费数据:9
3号消费者,消费数据:5
1号消费者,消费数据:8
2号生产者,产生数据: 10
2号消费者,消费数据:9
4号消费者,消费数据:10
5号消费者,消费数据:9