Go中Sync.Cond的介紹和使用

本篇內(nèi)容介紹了“Go中Sync.Cond的介紹和使用”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)網(wǎng)站建設(shè)由有經(jīng)驗(yàn)的網(wǎng)站設(shè)計(jì)師、開發(fā)人員和項(xiàng)目經(jīng)理組成的專業(yè)建站團(tuán)隊(duì),負(fù)責(zé)網(wǎng)站視覺設(shè)計(jì)、用戶體驗(yàn)優(yōu)化、交互設(shè)計(jì)和前端開發(fā)等方面的工作,以確保網(wǎng)站外觀精美、成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)易于使用并且具有良好的響應(yīng)性。

1. 程序中的通信方式

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

編程語言中,通信方式分為進(jìn)程間通信、線程間通信。

1.進(jìn)程間通信,常用方式:

  • 有名管道

  • 無名管道

  • 信號(hào)

  • 共享內(nèi)存

  • 消息隊(duì)列

  • 信號(hào)燈集

  • socket

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

  • 信號(hào)量

  • 互斥鎖

  • 條件變量

對(duì)于Go語言來說,Go程序啟動(dòng)之后對(duì)外是一個(gè)進(jìn)程,內(nèi)部包含若干協(xié)程,協(xié)程相當(dāng)于用戶態(tài)輕量級(jí)線程,所以協(xié)程的通信方式大多可以使用線程間通信方式來完成。

協(xié)程間通信方式,官方推薦使用channel,channel在一對(duì)一的協(xié)程之間進(jìn)行數(shù)據(jù)交換與通信十分便捷。但是,一對(duì)多的廣播場(chǎng)景中,則顯得有點(diǎn)無力,此時(shí)就需要sync.Cond來輔助。

2. 什么是廣播?

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

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

在Go語言中,則可以使用sync.Cond來實(shí)現(xiàn)多個(gè)協(xié)程之間的廣播通知功能。

3. sync.Cond

cond是sync包下面的一種數(shù)據(jù)類型,相當(dāng)于線程間通信的條件變量方式。

// 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  // 在第一次使用后不可復(fù)制,使用go vet作為檢測(cè)使用      // L is held while observing or changing the condition   // 根據(jù)需求初始化不同的鎖,如*Mutex 和 *RWMutex。注意是 指針類型     L Locker    // 具有頭尾指針的鏈表。存儲(chǔ)被阻塞的協(xié)程,通知時(shí)操作該鏈表中的協(xié)程     notify  notifyList     checker copyChecker  // 復(fù)制檢查,檢查cond實(shí)例是否被復(fù)制 }

該數(shù)據(jù)類型提供的方法有:

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

對(duì)應(yīng)源碼追溯

// 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是否是被復(fù)制的,如果是就panic     c.checker.check()     // 獲取等待隊(duì)列的一個(gè)ticket數(shù)值,作為喚醒時(shí)的一個(gè)令牌憑證     t := runtime_notifyListAdd(&c.notify)     // 解鎖     c.L.Unlock()        // 注意,上面的ticket數(shù)值會(huì)作為阻塞攜程的一個(gè)標(biāo)識(shí)     // 加入通知隊(duì)列里面     // 到這里執(zhí)行g(shù)opark(),當(dāng)前協(xié)程掛起,直到signal或broadcast發(fā)起通知     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)  // 隨機(jī)挑選一個(gè)進(jìn)行通知,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()     // 通知所有阻塞等待的協(xié)程     // 主要是喚醒 cond.notify 鏈表上的各個(gè)協(xié)程     runtime_notifyListNotifyAll(&c.notify) }

使用方法,代碼示例:

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

 總結(jié)

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

查看channel、sync.Cond源碼之后會(huì)發(fā)現(xiàn),它們有相似之處:

  1. 阻塞協(xié)程統(tǒng)一被封裝在 sudog 結(jié)構(gòu)里面

  2. channel阻塞讀/寫時(shí),用雙向鏈表存儲(chǔ)被阻塞導(dǎo)致等待喚醒的協(xié)程

  3. sync.Cond用帶有頭尾指針的單向鏈表存儲(chǔ)被阻塞導(dǎo)致等待喚醒的協(xié)程

  4. 阻塞時(shí)都是使用gopark()進(jìn)行協(xié)程的掛起操作

雖說有相似之處,但是卻有本質(zhì)區(qū)別:

  1. channel 可以用來在協(xié)程間傳遞數(shù)據(jù)

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

“Go中Sync.Cond的介紹和使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

當(dāng)前名稱:Go中Sync.Cond的介紹和使用
標(biāo)題來源:http://muchs.cn/article6/ppphig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)用戶體驗(yàn)、響應(yīng)式網(wǎng)站網(wǎng)站制作、定制開發(fā)、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化