這篇文章介紹了 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中文網其他相關文章!