您好,登錄后才能下訂單哦!
本篇內容介紹了“Go中sync包Cond使用場景是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
編寫代碼過程中, 通常有主協程和多個子協程進行協作的過程,比如通過 WaitGroup 可以實現當所有子協程完成之后, 主協程再繼續執行。
如上的場景是主協程等待子協程達到某個狀態再繼續運行。 但是反過來怎么操作呢,要求一組子協程等待主協達到某個狀態時才繼續運行。這個時候就需要用到 Cond 了
Cond 是和某個條件相關,在條件還沒有滿足的時候,所有等待這個條件的協程都會被阻塞住,只有這個條件滿足的時候,等待的協程才可能繼續進行下去。
Cond 在初始化的時候,需要關聯一個 Locker 接口的實例,一般會使用 Mutex 或者 RWMutex。
Cond 關聯的 Locker 實例可以通過 c.L 訪問,它內部維護著一個先入先出的等待隊列。
Cond 分別有三個方法
Wait
會把當前協程放入Cond的等待隊列中并阻塞,直到被Signal或者Broadcast方法從等待隊列中移除并喚醒,用于子協程阻塞。
Signal
主協程喚醒等待隊列中的一個子協程,先喚醒最先阻塞的子協程,被喚醒的子協程繼續執行。
Broadcast
主協程喚醒等待隊列中的全部協程,所有子協程繼續執行。
注意:調用Signal和Broadcast方法,不強求持有c.L的鎖,調用Wait方法是必須要持有c.L的鎖。
大家都去醫院先排隊,然后等待叫號,先排隊的先叫號。這次模擬有5個病人,分別先排隊。 然后護士根據排隊先后來叫號;
具體場景是,5個病人在三秒中之內分別排號,護士今天要叫5個號,一秒叫一個,叫完5個號就結束了
代碼如下:
package main import ( "fmt" "math/rand" "sync" "time" ) func main() { c := sync.NewCond(&sync.Mutex{}) num := 0 // 當前叫號是幾號 hand_num := 0 for i := 0; i < 5; i++ { go func(i int) { // 分別在不同時間排隊 time.Sleep(time.Second * time.Duration(rand.Int63n(10))) c.L.Lock() num++ // 當前取得號。 cur := num fmt.Printf("%s %d 號病人取到了 %d 號\n", time.Now().Format("2006-01-02 15:04:05"), i, cur) // 取到號了,等待叫號 c.Wait() fmt.Printf("%s %d 號病人排隊號是 %d 號,被叫號了\n", time.Now().Format("2006-01-02 15:04:05"), i, cur) hand_num = cur c.L.Unlock() }(i) } // 都叫號了 for hand_num != 5 { // 叫號 c.Signal() time.Sleep(time.Second * 1) } time.Sleep(time.Second * 10) }
執行結果如下
結果表明,5個病人,分別在三秒鐘內先后取號, 然后護士每過一秒鐘按照排隊的先后順序叫一個號(叫號的過程依然有病人取號),先取號的被先叫號。
此場景中,5個病人相當于5個協程, 主協程反復使用Signal()
按照順序一個個喚醒阻塞的子協程。
場景為如下: 運動員跑步比賽,要求8秒內全部運動員準備好,然后等待教練發令, 教練10秒后發令,所有運動員在發令后開始跑。
package main import ( "fmt" "math/rand" "sync" "time" ) func main() { c := sync.NewCond(&sync.Mutex{}) for i := 0; i < 10; i++ { go func(i int) { // 隨機一個8秒內的準備時間 time.Sleep(time.Second * time.Duration(rand.Int63n(8))) fmt.Printf("%s 運動員%d已準備就緒\n", time.Now().Format("2006-01-02 15:04:05"), i) c.L.Lock() // 準備完畢,等待教練發令 c.Wait() c.L.Unlock() fmt.Printf("%s 運動員%d開跑\n", time.Now().Format("2006-01-02 15:04:05"), i) }(i) } // 主協程等待10秒后發令 time.Sleep(time.Second * 10) fmt.Printf("%s 教練發令。\n", time.Now().Format("2006-01-02 15:04:05")) // 教練發令。通知所有運動員開始跑步, 即喚起之前 wait()的所有協程 c.Broadcast() // 等待跑步 time.Sleep(time.Second * 5) }
執行結果如下:
如結果所示, 10個運動員在8秒內分別準備好,等待教練發令后,同時開跑。
此場景中,10個運動員相當于10個協程, 同時等待主協程的命令,使用Broadcast()
喚醒所有阻塞的子協程。
使用 Cond,最容易踩的坑就是調用 Wait()
方法之前,調用者沒有持有鎖或沒有檢查輔助條件。
在如上示例代碼中,假如把調用 Wait()
方法前后的加鎖和釋放鎖的代碼注釋掉,運行代碼會導致程序 panic。原因是調用 Wait 方法,會先把調用者放入等待隊列中,然后釋放鎖。此時如果在未持有鎖時調用釋放鎖的方法,就會導致程序 panic。
“Go中sync包Cond使用場景是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。