- 之前在学习操作系统的时候,就知道生产者-消费者,但是概念是模模糊糊的,好像是一直没搞明白。
- 其实很简单嘛,生产者生产,消费者进行消费,就是如此简单。了解了一下go语言的goroutine,感觉实现并发原来可以如此简单,不像之前Java、C++,什么还需要什么线程池啥的。
单向channel最典型的应用是“生产者消费者模型”
所谓“生产者消费者模型”: 某个模块(函数等)负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、协程、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
单单抽象出生产者和消费者,还够不上是生产者/消费者模型。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
package main
import "fmt"
//import "time"
//此通道只能写,不能读
func producer(out chan<- int){
for i:=0;i<10;i++{
out<-i*i
}
close(out)
}
//此通大道只能读,不能写
func consumer(in <-chan int){
for num:=range in{
fmt.Println("num=",num)
}
}
func main(){
//创建双向,channel
ch:=make(chan int)
//生产者,生产数字,写入channel
//新开一个协程
go producer(ch) //channel传参,引用传递
//消费者,从channel读取内存,打印
consumer(ch)
简单说明:首先创建一个双向的channel,然后开启一个新的goroutine,把双向通道作为参数传递到producer方法中,同时转成只写通道。子协程开始执行循环,向只写通道中添加数据,这就是生产者。主协程,直接调用consumer方法,该方法将双向通道转成只读通道,通过循环每次从通道中读取数据,这就是消费者。
注意:channel作为参数传递,是引用传递。
实现斐波那契数列
//实现斐波那契数列:1 1 2 3 5 8
package main
import "fmt"
//此时的ch只写,quit只读
func fibonacci(ch chan<-int,quit <-chan bool){
x,y:=1,1
for {
//监听channel数据的流动
select {
case ch<-x:
x,y=y,x+y
case flag:=<-quit: //没数据时一直处于阻塞状态
fmt.Println("flag=",flag)
return //不能用break,因为只跳出select这一层
}
}
}
func main(){
//创建双向通道,没有缓冲的
ch:=make(chan int) //数字通信
quit:=make(chan bool) //程序是否结束
//生产者,从channel读取内容
//新建协程
go func(){
for i:=0;i<8;i++{
num:=<-ch //只读,没数据时,处于阻塞状态
fmt.Println("num=",num)
}
//可以停止
quit<-true //写
}()
//生产者,产生数字,写入channel
fibonacci(ch,quit)
}