在並發程式設計中,同步是防止資料競爭並確保執行緒或 goroutine 以協調方式運作的關鍵。 想像一下,您在協調多個生產者和消費者存取共享資源(例如緩衝區或佇列)時遇到問題。這種經典的並發挑戰稱為生產者-消費者問題。在這種情況下,同步對於確保生產者不會覆蓋資料以及消費者不會讀取無效或陳舊的資料至關重要。同步是必要的,因為如果沒有適當的同步,對共享資料的同時存取可能會導致競爭條件、資料損壞或崩潰。如果緩衝區已滿,生產者需要等待,如果緩衝區為空,消費者需要等待。 在某些情況下您有一個固定大小的有界緩衝區,並且您需要管理多個生產者和消費者對其的存取。
什麼是sync.Cond?
緩衝區(或佇列),其大小固定。多個生產者產生項目並將其新增至緩衝區,而多個消費者則從中刪除項目。挑戰是:
這是初始程式碼結構:
package main import ( "fmt" "sync" "time" ) const bufferSize = 5 type Buffer struct { data []int mu sync.Mutex cond *sync.Cond } func (b *Buffer) produce(item int) { // Producer logic to add item to the buffer } func (b *Buffer) consume() int { // Consumer logic to remove item from the buffer return 0 } func main() { buffer := &Buffer{data: make([]int, 0, bufferSize)} buffer.cond = sync.NewCond(&buffer.mu) var wg sync.WaitGroup // Start producer goroutines for i := 1; i <= 3; i++ { wg.Add(1) go func(id int) { defer wg.Done() for j := 0; j < 5; j++ { // Each producer creates 5 items buffer.produce(id*10 + j) // Produce unique items based on id and j time.Sleep(100 * time.Millisecond) } }(i) } // Start consumer goroutines for i := 1; i <= 3; i++ { wg.Add(1) go func(id int) { defer wg.Done() for j := 0; j < 5; j++ { // Each consumer consumes 5 items item := buffer.consume() fmt.Printf("Consumer %d consumed item %d\n", id, item) time.Sleep(150 * time.Millisecond) } }(i) } wg.Wait() fmt.Println("All producers and consumers finished.") }
身為工程師,我們的任務是實現生產和消費方法來實現這些要求。 Produce 方法將項目新增至緩衝區,並在新增項目時通知消費者。 Consumer 方法從緩衝區中刪除項目,並在項目被刪除時通知生產者。這個問題可以透過使用sync.Cond來等待並在緩衝區滿或空時發出訊號來無縫解決。
以下是如何在生產和消費方法中使用sync.Cond的詳細資訊:
初始化:
buffer.cond = sync.NewCond(&buffer.mu)
生產者方法(生產):
func (b *Buffer) produce(item int) { b.mu.Lock() defer b.mu.Unlock() // Wait if the buffer is full for len(b.data) == bufferSize { b.cond.Wait() // Release lock and wait until signaled } // Add item to the buffer b.data = append(b.data, item) fmt.Printf("Produced item %d\n", item) // Signal a consumer that an item is available b.cond.Signal() }
消費方法(消費):
func (b *Buffer) consume() int { b.mu.Lock() defer b.mu.Unlock() // Wait if the buffer is empty for len(b.data) == 0 { b.cond.Wait() // Release lock and wait until signaled } // Remove item from the buffer item := b.data[0] b.data = b.data[1:] fmt.Printf("Consumed item %d\n", item) // Signal a producer that space is available b.cond.Signal() return item }
在此範例中:
這種協調允許生產者和消費者在沒有乾擾或死鎖的情況下共享緩衝區,從而根據緩衝區的狀態有效地管理存取。
想像一下您的任務多個 goroutine 需要等待特定條件才能繼續,例如:
以上是了解Go中的sync.Cond:生產者-消費者場景中的Goroutine同步的詳細內容。更多資訊請關注PHP中文網其他相關文章!