Go中Sync.Cond的介紹和使用

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

創新互聯網站建設由有經驗的網站設計師、開發人員和項目經理組成的專業建站團隊,負責網站視覺設計、用戶體驗優化、交互設計和前端開發等方面的工作,以確保網站外觀精美、成都網站建設、網站建設易于使用并且具有良好的響應性。

1. 程序中的通信方式

GO語言中有句名言:“不要用共享內存來通信,而是使用通信來共享內存”。

編程語言中,通信方式分為進程間通信、線程間通信。

1.進程間通信,常用方式:

  • 有名管道

  • 無名管道

  • 信號

  • 共享內存

  • 消息隊列

  • 信號燈集

  • socket

2.線程間通信,常用方式:

  • 信號量

  • 互斥鎖

  • 條件變量

對于Go語言來說,Go程序啟動之后對外是一個進程,內部包含若干協程,協程相當于用戶態輕量級線程,所以協程的通信方式大多可以使用線程間通信方式來完成。

協程間通信方式,官方推薦使用channel,channel在一對一的協程之間進行數據交換與通信十分便捷。但是,一對多的廣播場景中,則顯得有點無力,此時就需要sync.Cond來輔助。

2. 什么是廣播?

舉個例子,上高中時,宿管老師每天早晨需要叫醒學生們去上課。這個時候,有兩種解決方法:①一個寢室一個寢室的把學生叫醒。②在宿舍樓安裝個廣播,到起床時間時,在廣播上叫醒學生。顯然,使用廣播的方式效率更高。

編程中的廣播可以理解為:多個操作流程依賴于一個操作流程完成后才能進行某種動作,這個被依賴的操作流程在喚醒所有依賴者時使用的一種通知方式。

在Go語言中,則可以使用sync.Cond來實現多個協程之間的廣播通知功能。

3. sync.Cond

cond是sync包下面的一種數據類型,相當于線程間通信的條件變量方式。

// Cond implements a condition variable, a rendezvous point // for goroutines waiting for or announcing the occurrence // of an event. // // Each Cond has an associated Locker L (often a *Mutex or *RWMutex), // which must be held when changing the condition and // when calling the Wait method. // // A Cond must not be copied after first use. type Cond struct {     noCopy noCopy  // 在第一次使用后不可復制,使用go vet作為檢測使用      // L is held while observing or changing the condition   // 根據需求初始化不同的鎖,如*Mutex 和 *RWMutex。注意是 指針類型     L Locker    // 具有頭尾指針的鏈表。存儲被阻塞的協程,通知時操作該鏈表中的協程     notify  notifyList     checker copyChecker  // 復制檢查,檢查cond實例是否被復制 }

該數據類型提供的方法有:

type Cond  func NewCond(l Locker) *Cond func (c *Cond) Broadcast() // 通知所有協程,廣播 func (c *Cond) Signal()  // 通知一個協程 func (c *Cond) Wait()  // 阻塞等待,直到被喚醒

對應源碼追溯

// Wait atomically unlocks c.L and suspends execution // of the calling goroutine. After later resuming execution, // Wait locks c.L before returning. Unlike in other systems, // Wait cannot return unless awoken by Broadcast or Signal. // // Because c.L is not locked when Wait first resumes, the caller // typically cannot assume that the condition is true when // Wait returns. Instead, the caller should Wait in a loop: //       //      注意下面的寫法是官方推薦的 //    c.L.Lock() //    for !condition() { //        c.Wait() //    } //    ... make use of condition ... //    c.L.Unlock() // func (c *Cond) Wait() {     // 檢查c是否是被復制的,如果是就panic     c.checker.check()     // 獲取等待隊列的一個ticket數值,作為喚醒時的一個令牌憑證     t := runtime_notifyListAdd(&c.notify)     // 解鎖     c.L.Unlock()        // 注意,上面的ticket數值會作為阻塞攜程的一個標識     // 加入通知隊列里面     // 到這里執行gopark(),當前協程掛起,直到signal或broadcast發起通知     runtime_notifyListWait(&c.notify, t)        // 被喚醒之后,先獲取鎖     c.L.Lock() }  // Signal wakes one goroutine waiting on c, if there is any. // // It is allowed but not required for the caller to hold c.L // during the call. func (c *Cond) Signal() {     c.checker.check()     runtime_notifyListNotifyOne(&c.notify)  // 隨機挑選一個進行通知,wait阻塞解除 }  // Broadcast wakes all goroutines waiting on c. // // It is allowed but not required for the caller to hold c.L // during the call. func (c *Cond) Broadcast() {     c.checker.check()     // 通知所有阻塞等待的協程     // 主要是喚醒 cond.notify 鏈表上的各個協程     runtime_notifyListNotifyAll(&c.notify) }

使用方法,代碼示例:

var locker sync.Mutex var cond = sync.NewCond(&locker)  // NewCond(l Locker)里面定義的是一個接口,擁有lock和unlock方法。 // 看到sync.Mutex的方法,func (m *Mutex) Lock(),可以看到是指針有這兩個方法,所以應該傳遞的是指針 func main() {     // 啟動多個協程     for i := 0; i < 10; i++ {         gofunc(x int) {             cond.L.Lock()          // 獲取鎖             defer cond.L.Unlock()  // 釋放鎖                        cond.Wait()   // 等待通知,阻塞當前 goroutine                        // 通知到來的時候, cond.Wait()就會結束阻塞, do something. 這里僅打印             fmt.Println(x)         }(i)     }        time.Sleep(time.Second * 1) // 睡眠 1 秒,等待所有 goroutine 進入 Wait 阻塞狀態     fmt.Println("Signal...")     cond.Signal()               // 1 秒后下發一個通知給已經獲取鎖的 goroutine        time.Sleep(time.Second * 1)     fmt.Println("Signal...")     cond.Signal()               // 1 秒后下發下一個通知給已經獲取鎖的 goroutine        time.Sleep(time.Second * 1)     cond.Broadcast()            // 1 秒后下發廣播給所有等待的goroutine     fmt.Println("Broadcast...")     time.Sleep(time.Second * 1) // 等待所有 goroutine 執行完畢 }

 總結

在Go中協程間通信的方式有多種,最常用的是channel。如果牽扯多個協程的通知,可以使用sync.Cond。

查看channel、sync.Cond源碼之后會發現,它們有相似之處:

  1. 阻塞協程統一被封裝在 sudog 結構里面

  2. channel阻塞讀/寫時,用雙向鏈表存儲被阻塞導致等待喚醒的協程

  3. sync.Cond用帶有頭尾指針的單向鏈表存儲被阻塞導致等待喚醒的協程

  4. 阻塞時都是使用gopark()進行協程的掛起操作

雖說有相似之處,但是卻有本質區別:

  1. channel 可以用來在協程間傳遞數據

  2. sync.Cond 不可以在協程間傳遞數據,主要用來進行協程的阻塞喚醒操作。如果需要傳遞數據,則需要全局變量進行傳遞

“Go中Sync.Cond的介紹和使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注創新互聯網站,小編將為大家輸出更多高質量的實用文章!

當前名稱:Go中Sync.Cond的介紹和使用
標題來源:http://m.kartarina.com/article6/ppphig.html

成都網站建設公司_創新互聯,為您提供品牌網站建設用戶體驗響應式網站網站制作定制開發企業建站

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都seo排名網站優化
主站蜘蛛池模板: 亚洲精品无码久久千人斩| 97性无码区免费| 国产精品亚洲а∨无码播放麻豆| av大片在线无码免费| 国内精品久久久久久无码不卡| 一本一道av中文字幕无码| 无码国产精品一区二区免费模式| 亚洲AV无码专区亚洲AV桃| YY111111少妇无码理论片| 制服在线无码专区| 亚洲乱亚洲乱少妇无码| 少妇人妻偷人精品无码AV | 亚洲精品无码成人AAA片| 无码人妻丝袜在线视频| 国产成人无码一区二区三区| 国产精品成人无码免费| 亚洲日韩一区二区一无码| 国产精品va无码一区二区| 日韩av片无码一区二区三区不卡| 日韩乱码人妻无码中文字幕久久| 亚洲AV无码乱码精品国产| 亚洲youwu永久无码精品| 国产激情无码一区二区| 国产AV无码专区亚洲AV漫画 | 国产综合无码一区二区色蜜蜜| 久久亚洲精品无码| 国精无码欧精品亚洲一区| 人妻无码aⅴ不卡中文字幕| 少妇特殊按摩高潮惨叫无码| 中文字幕无码亚洲欧洲日韩| 日韩人妻无码一区二区三区久久| 亚洲AV中文无码乱人伦下载| 国产成人无码一区二区在线观看 | 国产AV无码专区亚洲Av| 潮喷失禁大喷水aⅴ无码| 国产亚洲美日韩AV中文字幕无码成人 | 日韩精品中文字幕无码专区| 亚洲AV无码XXX麻豆艾秋| 无码人妻精品一区二区蜜桃网站 | 日韩人妻无码一区二区三区久久| 无码人妻AⅤ一区二区三区|