Go中協程間通訊的方式Sync.Cond
導讀 | 在Go中協程間通訊的方式有多種,最常用的是channel。如果牽扯多個協程的通知,可以使用sync.Cond。 |
GO語言中有句名言:“不要用共享記憶體來通訊,而是使用通訊來共享記憶體”。
程式語言中,通訊方式分為程式間通訊、執行緒間通訊。
1.程式間通訊,常用方式:
- 有名管道
- 無名管道
- 訊號
- 共享記憶體
- 訊息佇列
- 訊號燈集
- socket
2.執行緒間通訊,常用方式:
- 訊號量
- 互斥鎖
- 條件變數
對於Go語言來說,Go程式啟動之後對外是一個程式,內部包含若干協程,協程相當於使用者態輕量級執行緒,所以協程的通訊方式大多可以使用執行緒間通訊方式來完成。
協程間通訊方式,官方推薦使用channel,channel在一對一的協程之間進行資料交換與通訊十分便捷。但是,一對多的廣播場景中,則顯得有點無力,此時就需要sync.Cond來輔助。
舉個例子,上高中時,宿管老師每天早晨需要叫醒學生們去上課。這個時候,有兩種解決方法:①一個寢室一個寢室的把學生叫醒。②在宿舍樓安裝個廣播,到起床時間時,在廣播上叫醒學生。顯然,使用廣播的方式效率更高。
程式設計中的廣播可以理解為:多個操作流程依賴於一個操作流程完成後才能進行某種動作,這個被依賴的操作流程在喚醒所有依賴者時使用的一種通知方式。
在Go語言中,則可以使用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。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2776667/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一種go協程間記憶體零拷貝的訊息通訊機制Go記憶體
- Vue 元件間的通訊方式Vue元件
- 理解 Go 中的協程(Goroutine)Go
- 在Linux中,程序間通訊方式有哪些?Linux
- 程式間的幾種通訊方式
- React中元件間通訊的方式React元件
- Vue中元件間通訊的方式Vue元件
- Go中協程死鎖Go
- 程式間通訊方式有哪些?
- iOS app之間通訊方式iOSAPP
- React中元件之間通訊的方式React元件
- Swoole協程與Go協程的區別Go
- Swoole 協程與 Go 協程的區別Go
- python 協程與go協程的區別PythonGo
- 程式間的五種通訊方式介紹
- Vue元件之間通訊的三種方式Vue元件
- React Components之間的通訊方式瞭解下React
- SpringCloud-服務間通訊方式SpringGCCloud
- 什麼是程式間通訊?Linux程式間通訊有幾種方式?Linux
- 程式間通訊是什麼?Linux程式間通訊有幾種方式?Linux
- 在Go和Python之間通過ActiveMQ通訊GoPythonMQ
- 前端學習(2370):元件之間的通訊方式前端元件
- 前端學習(2371):元件之間的通訊方式前端元件
- 程式間的五種通訊方式介紹-詳解
- Go 併發 -- 協程Go
- 程序間的通訊(訊號通訊)
- 程式間的八種通訊方式----共享記憶體是最快的 IPC 方式記憶體
- Go語言—sync.Cond原始碼分析Go原始碼
- Web發展中通訊的方式有哪些Web
- Linux程式間的通訊方式有哪些?Linux入門教程Linux
- 使用go net實現簡單的redis通訊協議YWSVGoRedis協議
- 我最喜歡的程式之間通訊方式-訊息匯流排
- 用 Go 來了解一下 Redis 通訊協議GoRedis協議
- 微服務之間的協作方式微服務
- T面試題:程式間的通訊方式有哪幾種?面試題
- 程式間的通訊
- Go實戰-基於Go協程和channel的使用Go
- 程序通訊方式