这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战
本文收录于我的专栏:《让我们一起Golang》
Golang高并发:生产者消费者模型
我们本篇博文主要通过几个例子来介绍生产者消费者模型。
案例1
下面看看第一个例子中的生产者协程。
//生产者协程
go func() {
for {
product := strconv.Itoa(time.Now().Nanosecond())
chanShop <- "商品" + product
fmt.Println("生产了商品",product)
time.Sleep(1000 * time.Millisecond)
}
}()
生产者协程就是源源不断的生产,将时间转化为字符串,然后源源不断的产生产品字符串。此处用到了strconv.Itoa(),是将整型转换为字符串类型。time.Now()是当前的时间,而使用Nanosecond()是将其转换为纳秒。然后将得到的产品序列号字符串放入视频管道,然后输出生产了什么产品,然后睡一秒,然后接着生产。
至于消费者协程,我相信你已经猜到了是什么了,我们也来看一看吧。
//消费者协程
go func() {
for{
product := <-chanShop
fmt.Println("消费了产品",product)
time.Sleep(time.Second)
}
}()
每次从商品管道取一个产品,然后输出消费了什么产品,然后睡一秒,然后继续消费。
再来看看这个案例的主协程
//主协程
for {
time.Sleep(time.Second)
}
运行结果是
消费了产品 商品607861100
生产了商品 607861100
生产了商品 607929500
消费了产品 商品607929500
生产了商品 608013000
消费了产品 商品608013000
生产了商品 608018400
消费了产品 商品608018400
没错,源源不断的生产消费、生产消费。
案例2
我们再来看看第二个案例,这个案例,我们引入了”物流“的概念。
先上主函数给各位读者老爷看看吧:
func main() {
chanStorage := make(chan string ,100)
chanShop := make(chan string, 100)
go producer(chanStorage)
go logistics(chanStorage,chanShop)
go consumer(chanShop)
for {
time.Sleep(time.Second)
}
}
主要是建立商店和物流两条管道,然后建立生产者、消费者、物流三条协程,然后主协程一直不go die。
然后先来看看生产者协程
func producer(chanStorage chan string) {
for i:=0;i<10;i++{
product := strconv.Itoa(time.Now().Nanosecond())
chanStorage <- "产品"+product
fmt.Println("生产了产品",product)
time.Sleep(time.Second)
}
close(chanStorage)
}
和第一个案例一样,不过我们只生产10个产品放入仓库,然后关闭了仓库。
然后看看物流协程是干了些什么:
func logistics(chanStroge,chanShop chan string) {
for p:= range chanStroge{
fmt.Println("物流完成转运",p)
chanShop <- p
}
fmt.Println("商品转运完毕!")
}
源源不断扫描仓库,拿出商品然后将商品转运到商店。当生产者关闭仓库后,物流也停止转运了。
消费者不断在消费,然后看看消费者:
func consumer(chanShop chan string) {
for{
product := <-chanShop
fmt.Println("消费了产品",product)
}
}
等来一件商品,就卖出去。
然后看看运行结果
生产了产品 605763200
物流完成转运 产品605763200
消费了产品 产品605763200
生产了产品 605826700
物流完成转运 产品605826700
消费了产品 产品605826700
生产了产品 619889800
物流完成转运 产品619889800
消费了产品 产品619889800
生产了产品 619906200
物流完成转运 产品619906200
消费了产品 产品619906200
生产了产品 627948700
物流完成转运 产品627948700
消费了产品 产品627948700
我们可以看到,生产、转运、消费几乎是同时的。
因为我们当物流公司停止运物资时,商店也要关门,所以在物流协程内加入:
close(chanShop)
fmt.Println("商品转运完毕!商店已关张!")
然后继续把消费者的for循环替换成
for product := range chanShop{
//product := <-chanShop
fmt.Println("消费了产品",product)
fmt.Println()
}
fmt.Println("消费全部完毕!")
就能够只读取管道里面的商品。