Golang:再谈生产者消费者模型

2,785 阅读2分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

本文收录于我的专栏:《让我们一起Golang》

Golang:再谈生产者消费者模型

那假如我们想生产完了之后在一次性消费呢?怎么实现这个呢?那我们就出现了调度的情形。消费者等生产者生产完毕的信号,只有生产者给消费者发送信号,消费者才能消费,不然消费者一直阻塞。

主函数

我们先来看看主函数:

func main() {
    chanShop := make(chan string,10)
    chanTel  := make(chan int)
    
    go Producer(chanShop,chanTel)
    go Consumer(chanShop,chanTel)
​
    for  {
        time.Sleep(time.Second)
    }
}

chanTel没有缓存能力,我们之前说的,如果不往里写,那根本就不能读。所以被阻塞的那条消费者协程在读取前几乎不占用资源。

生产者协程

再来看看生产者协程:

func Producer(chanShop chan string,chanTel chan int)  {
    runtime.GOMAXPROCS(2)
    for i:=0;i<10;i++ {
        product := strconv.Itoa(time.Now().Nanosecond())
        chanShop <- "产品"+product
        fmt.Println("生产了产品",product)
        time.Sleep(time.Second)
    }
    close(chanShop)
    fmt.Println("生产完毕")
    chanTel <- 123456789
    fmt.Println(123456789,"呼出电话")
}

生产10个商品,生产完毕之后,就开始打电话,给消费者协程打电话。生产者协程给chanTel写入东西,阻塞的消费者协程立刻就通顺了,来看看消费者协程的内容吧!

消费者协程

func Consumer(chanShop chan string,chanTel chan int)  {
    runtime.GOMAXPROCS(1)
    
    tel := <- chanTel
    fmt.Println("收到来电",tel)
​
    for product := range chanShop{
        fmt.Println("消费了产品",product)
    }
    fmt.Println("消费完毕")
}

消费者调用单核处理消费。当收到来电时,该协程就不阻塞了,马上消费产品!

看了上面的例子,你可能还会疑惑什么是生产者消费者问题,最后我们再来了解了解吧!

什么是生产者消费者问题

根据维基百科,生产者消费者问题是这样介绍的:

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是一个多进程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

我们这段代码只是简单的描述这个问题,在写入缓冲区完毕后,缓冲区大小为10,我们就写入10个,然后就马上关闭chanShop,关闭后消费者协程就不会一直读而导致在缓冲区中空时尝试读取数据。