中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go中sync包Cond使用場景是什么

發布時間:2023-03-07 17:44:34 來源:億速云 閱讀:92 作者:iii 欄目:開發技術

本篇內容介紹了“Go中sync包Cond使用場景是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    背景

    編寫代碼過程中, 通常有主協程和多個子協程進行協作的過程,比如通過 WaitGroup 可以實現當所有子協程完成之后, 主協程再繼續執行。

    如上的場景是主協程等待子協程達到某個狀態再繼續運行。 但是反過來怎么操作呢,要求一組子協程等待主協達到某個狀態時才繼續運行。這個時候就需要用到 Cond 了

    Cond 簡介

    Cond 是和某個條件相關,在條件還沒有滿足的時候,所有等待這個條件的協程都會被阻塞住,只有這個條件滿足的時候,等待的協程才可能繼續進行下去。
    Cond 在初始化的時候,需要關聯一個 Locker 接口的實例,一般會使用 Mutex 或者 RWMutex。
    Cond 關聯的 Locker 實例可以通過 c.L 訪問,它內部維護著一個先入先出的等待隊列。
    Cond 分別有三個方法

    • Wait

    會把當前協程放入Cond的等待隊列中并阻塞,直到被Signal或者Broadcast方法從等待隊列中移除并喚醒,用于子協程阻塞。

    • Signal

    主協程喚醒等待隊列中的一個子協程,先喚醒最先阻塞的子協程,被喚醒的子協程繼續執行。

    • Broadcast

    主協程喚醒等待隊列中的全部協程,所有子協程繼續執行。

    注意:調用Signal和Broadcast方法,不強求持有c.L的鎖,調用Wait方法是必須要持有c.L的鎖。

    使用示例

    Signal的使用場景

    大家都去醫院先排隊,然后等待叫號,先排隊的先叫號。這次模擬有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)
    }

    執行結果如下

    Go中sync包Cond使用場景是什么

    結果表明,5個病人,分別在三秒鐘內先后取號, 然后護士每過一秒鐘按照排隊的先后順序叫一個號(叫號的過程依然有病人取號),先取號的被先叫號。
    此場景中,5個病人相當于5個協程, 主協程反復使用Signal() 按照順序一個個喚醒阻塞的子協程。

    Broadcast的使用場景

    場景為如下: 運動員跑步比賽,要求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)
    }

    執行結果如下:

    Go中sync包Cond使用場景是什么

    如結果所示, 10個運動員在8秒內分別準備好,等待教練發令后,同時開跑。
    此場景中,10個運動員相當于10個協程, 同時等待主協程的命令,使用Broadcast() 喚醒所有阻塞的子協程。

    注意事項

    使用 Cond,最容易踩的坑就是調用 Wait() 方法之前,調用者沒有持有鎖或沒有檢查輔助條件。
    在如上示例代碼中,假如把調用 Wait() 方法前后的加鎖和釋放鎖的代碼注釋掉,運行代碼會導致程序 panic。原因是調用 Wait 方法,會先把調用者放入等待隊列中,然后釋放鎖。此時如果在未持有鎖時調用釋放鎖的方法,就會導致程序 panic。

    “Go中sync包Cond使用場景是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    武陟县| 鄂尔多斯市| 上林县| 尉犁县| 贵南县| 东源县| 得荣县| 衡阳县| 平度市| 土默特右旗| 夏河县| 浮梁县| 绥德县| 翼城县| 汕尾市| 武安市| 民县| 罗江县| 阿克苏市| 怀安县| 闽侯县| 天台县| 云霄县| 磴口县| 辛集市| 云龙县| 普宁市| 洛宁县| 鲜城| 沙坪坝区| 莱芜市| 黑水县| 安泽县| 玉屏| 雷州市| 重庆市| 来宾市| 凤阳县| 台东县| 固镇县| 库尔勒市|