Go?WaitGroup及Cond底層實(shí)現(xiàn)原理
WaitGroup
概念
Go標(biāo)準(zhǔn)庫提供了WaitGroup原語, 可以用它來等待一批 Goroutine 結(jié)束
底層數(shù)據(jù)結(jié)構(gòu)
// A WaitGroup must not be copied after first use.
type WaitGroup struct {
noCopy noCopy
state1 [3]uint32
}
其中 noCopy 是 golang 源碼中檢測(cè)禁止拷貝的技術(shù)。如果程序中有 WaitGroup 的賦值行為,使用 go vet 檢查程序時(shí),就會(huì)發(fā)現(xiàn)有報(bào)錯(cuò)。但需要注意的是,noCopy 不會(huì)影響程序正常的編譯和運(yùn)行。
state1主要是存儲(chǔ)著狀態(tài)和信號(hào)量,狀態(tài)維護(hù)了 2 個(gè)計(jì)數(shù)器,一個(gè)是請(qǐng)求計(jì)數(shù)器counter ,另外一個(gè)是等待計(jì)數(shù)器waiter(已調(diào)用 WaitGroup.Wait 的 goroutine 的個(gè)數(shù))
當(dāng)數(shù)組的首地址是處于一個(gè)8字節(jié)對(duì)齊的位置上時(shí),那么就將這個(gè)數(shù)組的前8個(gè)字節(jié)作為64位值使用表示狀態(tài),后4個(gè)字節(jié)作為32位值表示信號(hào)量(semaphore);同理如果首地址沒有處于8字節(jié)對(duì)齊的位置上時(shí),那么就將前4個(gè)字節(jié)作為semaphore,后8個(gè)字節(jié)作為64位數(shù)值。

使用方法
在WaitGroup里主要有3個(gè)方法:
WaitGroup.Add():可以添加或減少請(qǐng)求的goroutine數(shù)量,Add(n) 將會(huì)導(dǎo)致 counter += n
WaitGroup.Done():相當(dāng)于Add(-1),Done() 將導(dǎo)致 counter -=1,請(qǐng)求計(jì)數(shù)器counter為0 時(shí)通過信號(hào)量調(diào)用runtime_Semrelease喚醒waiter線程
WaitGroup.Wait():會(huì)將 waiter++,同時(shí)通過信號(hào)量調(diào)用 runtime_Semacquire(semap)阻塞當(dāng)前 goroutine
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
println("hello")
}()
}
wg.Wait()
}
Cond
概念
Go標(biāo)準(zhǔn)庫提供了Cond原語,可以讓 Goroutine 在滿足特定條件時(shí)被阻塞和喚醒
底層數(shù)據(jù)結(jié)構(gòu)
type Cond struct {
noCopy noCopy
// L is held while observing or changing the condition
L Locker
notify notifyList
checker copyChecker
}
type notifyList struct {
wait uint32
notify uint32
lock uintptr // key field of the mutex
head unsafe.Pointer
tail unsafe.Pointer
}
主要有4個(gè)字段:
nocopy : golang 源碼中檢測(cè)禁止拷貝的技術(shù)。如果程序中有 WaitGroup 的賦值行為,使用 go vet 檢查程序時(shí),就會(huì)發(fā)現(xiàn)有報(bào)錯(cuò),但需要注意的是,noCopy 不會(huì)影響程序正常的編譯和運(yùn)行
checker:用于禁止運(yùn)行期間發(fā)生拷貝,雙重檢查(Double check)
L:可以傳入一個(gè)讀寫鎖或互斥鎖,當(dāng)修改條件或者調(diào)用Wait方法時(shí)需要加鎖
notify:通知鏈表,調(diào)用Wait()方法的Goroutine會(huì)放到這個(gè)鏈表中,從這里獲取需被喚醒的Goroutine列表
使用方法
在Cond里主要有3個(gè)方法:
sync.NewCond(l Locker): 新建一個(gè) sync.Cond 變量,注意該函數(shù)需要一個(gè) Locker 作為必填參數(shù),這是因?yàn)樵?nbsp;cond.Wait()中底層會(huì)涉及到 Locker 的鎖操作Cond.Wait(): 阻塞等待被喚醒,調(diào)用Wait函數(shù)前需要先加鎖;并且由于Wait函數(shù)被喚醒時(shí)存在虛假喚醒等情況,導(dǎo)致喚醒后發(fā)現(xiàn),條件依舊不成立,因此需要使用 for 語句來循環(huán)地進(jìn)行等待,直到條件成立為止Cond.Signal(): 只喚醒一個(gè)最先 Wait 的 goroutine,可以不用加鎖Cond.Broadcast(): 喚醒所有Wait的goroutine,可以不用加鎖
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
var status int64
func main() {
c := sync.NewCond(&sync.Mutex{})
for i := 0; i < 10; i++ {
go listen(c)
}
go broadcast(c)
time.Sleep(1 * time.Second)
}
func broadcast(c *sync.Cond) {
// 原子操作
atomic.StoreInt64(&status, 1)
c.Broadcast()
}
func listen(c *sync.Cond) {
c.L.Lock()
for atomic.LoadInt64(&status) != 1 {
c.Wait()
// Wait 內(nèi)部會(huì)先調(diào)用 c.L.Unlock(),來先釋放鎖,如果調(diào)用方不先加鎖的話,會(huì)報(bào)錯(cuò)
}
fmt.Println("listen")
c.L.Unlock()
}以上就是Go WaitGroup及Cond底層實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于Go WaitGroup Cond原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Beego中ORM操作各類數(shù)據(jù)庫連接方式詳細(xì)示例
這篇文章主要為大家介紹了Beego中ORM操作各類數(shù)據(jù)庫連接方式詳細(xì)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
一文詳解GO如何實(shí)現(xiàn)Redis的AOF持久化
這篇文章主要為大家詳細(xì)介紹了GO如何實(shí)現(xiàn)Redis的AOF持久化的,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-03-03
Golang實(shí)現(xiàn)Redis事務(wù)深入探究
這篇文章主要介紹了Golang實(shí)現(xiàn)Redis事務(wù)深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
使用Lumberjack+zap進(jìn)行日志切割歸檔操作
這篇文章主要介紹了使用Lumberjack+zap進(jìn)行日志切割歸檔操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
解決Golang小數(shù)float64在實(shí)際工程中加減乘除的精度問題
這篇文章主要介紹了解決Golang小數(shù)float64在實(shí)際工程中加減乘除的精度問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
深入講解Go語言中函數(shù)new與make的使用和區(qū)別
大家都知道Go語言中的函數(shù)new與函數(shù)make一直是新手比較容易混淆的東西,看著相似,但其實(shí)不同,不過解釋兩者之間的不同也非常容易,下面這篇文章主要給大家介紹了關(guān)于Go語言中函數(shù)new與make區(qū)別的相關(guān)資料,需要的朋友可以參考下。2017-10-10
golang定時(shí)任務(wù)cron項(xiàng)目實(shí)操指南
Go實(shí)現(xiàn)的cron 表達(dá)式的基本語法跟linux 中的 crontab基本是類似的,下面這篇文章主要給大家介紹了關(guān)于golang定時(shí)任務(wù)cron項(xiàng)目實(shí)操的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12

