日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Go中協(xié)程間通信的方式Sync.Cond

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

創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、做網(wǎng)站、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的臨汾網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

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 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。


本文標(biāo)題:Go中協(xié)程間通信的方式Sync.Cond
轉(zhuǎn)載來于:http://www.dlmjj.cn/article/cdipchs.html