首頁  >  文章  >  後端開發  >  生產者-消費者模式

生產者-消費者模式

王林
王林原創
2024-07-27 14:35:15831瀏覽

Producer-Consumer Pattern

這篇文章介紹了 Goroutine 和 Channels。這是 Go 中最有用的兩個結構。如果正確使用,它們可以為開發人員提供處理並發性的極大靈活性。它們是訪談中最常見的話題之一。

在 Go 中實作簡單的生產者消費者模式。

var buffer = make(chan int, 5)

func produce(wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        buffer <- i
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(100)))
    }
    fmt.Println("producer done")
}

func consume(wg *sync.WaitGroup) {
    defer wg.Done()
    for data := range buffer {
        fmt.Println(data)
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(400)))
    }
    fmt.Println("consumer done")
}

func main() {
    var producerWg sync.WaitGroup
    var consumerWg sync.WaitGroup
    producerWg.Add(1)
    go produce(&producerWg)
    go func() {
        producerWg.Wait()
        close(buffer)
        fmt.Println("closed channel")
    }()
    consumerWg.Add(1)
    go consume(&consumerWg)
    consumerWg.Wait()
    fmt.Println("done")
}

這是最簡單的實作之一;但這種模式很常見。我們有一個「產生」值的線程和一個必須「消耗」它們的線程。在golang中,在執行緒之間傳遞這些值的方式是通道。

我們先為整數建立一個通道。然後建立實現生產者和消費者函數的例程。

在任何多執行緒情況下,同步都是一個問題。 Golang 創建了 WaitGroup 作為實現同步的一種手段。它們只是作為計數器工作,需要同步的線程將等待,直到計數為 0。控制執行緒使用 Done() 函數來遞減計數器。

在此問題中,我們為生產者和消費者建立一個 WaitGroup,並將兩者初始化為計數 1(使用 Add() 函數)。

主線程啟動生產者、消費者和一個等待生產者的內聯線程,然後等待消費者完成。

生產者執行緒開始正常發送資料。完成後,它使用 WaitGroup 來表示已完成向通道的發送。內嵌 goroutine 等待關閉通道的生產者 WaitGroup。如果通道永遠不會關閉,消費者將永遠休眠等待更多數據,並且進程永遠不會終止。

當消費者沒有更多資料時(因為通道已關閉),它會通知第二個 WaitGroup 已完成。

啟動生產者和消費者執行緒的主執行緒將等待,直到消費者WaitGroup允許它完成。這可以防止主執行緒過早終止,從而殺死進程中的所有執行緒。

這不是實現生產者-消費者模式的唯一方法。

還有一些問題,例如 SIGTERM 和 SIGINT 等訊號的外部終止,需要在生產程式碼中解決。這是一個簡單的演示,展示了基礎知識。

您還會如何實現它?上述實現缺少什麼?在下面發表您的評論或其他實現的連結。

謝謝!

這篇文章以及本系列所有文章的程式碼可以在這裡找到

以上是生產者-消費者模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn