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("消费全部完毕!")
复制代码
就能够只读取管道里面的商品。
评论