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()

至于消费者协程,我相信你已经猜到了是什么了,我们也来看一看吧。

//消费者协程
    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("消费全部完毕!")

就能够只读取管道里面的商品。