Go sync.Cond:最容易被忽視的同步機制

技术颜良發表於2024-11-28
Go sync.Cond:最容易被忽視的同步機制
原創 Go Official Blog Go Official Blog
2024年11月17日 17:56 中國香港 1人
引言
在探討 Go 語言中的同步機制時,大多數開發者都熟悉 sync.Mutex 和 sync.RWMutex。然而,還有一個強大但經常被忽視的同步原語:sync.Cond。本文將詳細介紹 sync.Cond,解釋它的工作原理,並透過實際示例說明其應用場景。
什麼是 sync.Cond?
當一個 goroutine 需要等待一些特定的事情發生時,例如一些共享資料發生變化,它就會 "阻塞",這意味著它只是暫停工作,直到獲得繼續工作的許可。最基本的方法是使用迴圈,甚至可以新增 time.Sleep,以防止 CPU 忙碌等待而發瘋。
sync.Cond 是一個條件變數,它提供了一種等待和通知 goroutine 的機制。它在需要多個 goroutine 基於某個條件進行協調的場景中特別有用。
圖片
基本語法如下:
var mu sync.Mutex
cond := sync.NewCond(&mu)
sync.Cond 主要提供三個方法:
Wait() - 暫停當前 goroutine 的執行,直到收到通知
Signal() - 喚醒一個等待的 goroutine
Broadcast() - 喚醒所有等待的 goroutine
實際示例
讓我們透過一個佇列處理的例子來理解 sync.Cond 的用法:
type Queue struct {
cond *sync.Cond
data []interface{}
capacity int
}
func NewQueue(capacity int) *Queue {
return &Queue{
cond: sync.NewCond(&sync.Mutex{}),
capacity: capacity,
}
}
func (q *Queue) Put(item interface{}) {
q.cond.L.Lock()
defer q.cond.L.Unlock()
// 當佇列已滿時等待
for len(q.data) == q.capacity {
q.cond.Wait()
}
q.data = append(q.data, item)
// 通知等待中的消費者
q.cond.Signal()
}
func (q *Queue) Get() interface{} {
q.cond.L.Lock()
defer q.cond.L.Unlock()
// 當佇列為空時等待
for len(q.data) == 0 {
q.cond.Wait()
}
item := q.data[0]
q.data = q.data[1:]
// 通知等待中的生產者
q.cond.Signal()
return item
}
sync.Cond 的關鍵特性
避免虛假喚醒:
for !condition() {
cond.Wait()
}
使用 for 迴圈而不是 if 語句來檢查條件,這樣可以防止虛假喚醒。
必須持有鎖:
呼叫 Wait() 前必須持有鎖 Wait() 會自動釋放鎖,並在被喚醒時重新獲取鎖 Signal vs Broadcast:Signal() 只喚醒一個等待的 goroutine Broadcast() 喚醒所有等待的 goroutine 適用場景
生產者-消費者模式
資源池管理
任務佇列處理
等待特定條件滿足
示例:等待特定條件
type Server struct {
cond *sync.Cond
ready bool
}
func NewServer() *Server {
return &Server{
cond: sync.NewCond(&sync.Mutex{}),
}
}
func (s *Server) WaitForReady() {
s.cond.L.Lock()
defer s.cond.L.Unlock()
for !s.ready {
s.cond.Wait()
}
}
func (s *Server) SetReady() {
s.cond.L.Lock()
s.ready = true
s.cond.L.Unlock()
s.cond.Broadcast()
}
###最佳實踐
始終使用 for 迴圈進行條件檢查
確保正確的鎖定/解鎖操作
適當選擇 Signal() 或 Broadcast()
避免在持有鎖時執行耗時操作
效能考慮 - sync.Cond 在以下情況下特別高效:
多個 goroutine 需要等待特定條件
條件滿足時只需要喚醒部分而非全部 goroutine
需要精確控制 goroutine 的喚醒時機
結論
sync.Cond 是 Go 語言中一個強大但常被忽視的同步工具。它在需要基於條件協調多個 goroutine 的場景中特別有用。透過合理使用 sync.Cond,我們可以實現更高效和優雅的併發控制。
Go Official Blog
你的肯定是對我最大的鼓勵
閱讀 703

相關文章