前面已经讲过不少Golang系列知识,包括并发,锁等内容,感兴趣的能够看看之前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,html
接下来说几个golang常见的并发模型,今天先说说生产者消费者模型。golang
生产者:发送数据端缓存
消费者:接收数据端安全
缓冲区:
1. 解耦(下降生产者和消费者之间耦合度)并发
2. 并发(生产者消费者数量不对等时,能保持正常通讯)函数
3. 缓存(生产者和消费者 数据处理速度不一致时,暂存数据)spa
生产者消费者模型是很是常见的并发模型,并且golang提供了chan类型,能够很方便的实现。指针
根据 golang的官方文档,使用chan就能够实现生产者和消费者之间的数据和状态同步。code
package main
import "fmt"
func Producer(ch chan int) {
for i := 1; i <= 10; i++ {
ch <- i
}
close(ch)
}
func Consumer(id int, ch chan int, done chan bool) {
for {
value, ok := <-ch
if ok {
fmt.Printf("id: %d, recv: %d\n", id, value)
} else {
fmt.Printf("id: %d, closed\n", id)
break
}
}
done <- true
}
func main() {
ch := make(chan int, 3)
coNum := 2
done := make(chan bool, coNum)
for i := 1; i <= coNum; i++ {
go Consumer(i, ch, done)
}
go Producer(ch)
for i := 1; i <= coNum; i++ {
<-done
}
}orm
运行结果:
id: 2, recv: 1
id: 1, recv: 2
id: 1, recv: 4
id: 1, recv: 5
id: 1, recv: 6
id: 2, recv: 3
id: 2, recv: 8
id: 2, recv: 9
id: 2, recv: 10
id: 2, closed
id: 1, recv: 7
id: 1, closed
简单说明:
一、首先建立一个双向的channel,
2.、而后开启一个新的goroutine,把双向通道做为参数传递到producer方法中,同时转成只写通道。子协程开始执行循环,向只写通道中添加数据,这就是生产者。
三、主协程,直接调用consumer方法,该方法将双向通道转成只读通道,经过循环每次从通道中读取数据,这就是消费者。
注意:channel做为参数传递,是引用传递。
1:解耦
假设生产者和消费者分别是两个类。若是让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。未来若是消费者的代码发生变化,可能会直接影响到生产者。而若是二者都依赖于某个缓冲区,二者之间不直接依赖,耦合度也就相应下降了。
2:处理并发
生产者直接调用消费者的某个方法,还有另外一个弊端。因为函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回以前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者只能无故浪费时间。
使用了生产者/消费者模式以后,生产者和消费者能够是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就能够再去生产下一个数据。基本上不用依赖消费者的处理速度。
其实最当初这个生产者消费者模式,主要就是用来处理并发问题的。
3:缓存
若是生产者制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据能够暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
以上,就把golang生产者消费者模型简单介绍完了,但愿能对你们有所帮助。