天天看點

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("消費全部完畢!")           

就能夠隻讀取管道裡面的商品。