您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“GO中sync包自由控制并發(fā)的方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“GO中sync包自由控制并發(fā)的方法”吧!
channel 常用于并發(fā)通信,要保證并發(fā)安全,主要使用互斥鎖。在并發(fā)的過程中,當(dāng)一個內(nèi)存被多個 goroutine 同時訪問時,就會產(chǎn)生資源競爭的情況。這塊內(nèi)存也可以稱為共享資源。
并發(fā)時對于共享資源必然會出現(xiàn)搶占資源的情況,如果是對某資源的統(tǒng)計,很可能就會導(dǎo)致結(jié)果錯誤。為保證只有一個協(xié)程拿到資源并操作它,可以引入互斥鎖 sync.Mutex。
互斥鎖,指的是并發(fā)時,在同一時刻只有一個協(xié)程執(zhí)行某段代碼,其他協(xié)程只有等待該協(xié)程執(zhí)行完成后才能繼續(xù)執(zhí)行。
var (sum int mutex sync.Mutex) func add(i int){ mutex.Lock() sum+=i mute.Unlock() }
使用 mutex 加鎖保護 sum+ =i 的代碼片段,這樣這個片段區(qū)就無法同時被多個協(xié)程訪問,當(dāng)有協(xié)程進入該片段區(qū),那其他的協(xié)程就只有等待,以此保證臨界區(qū)的并發(fā)安全。
sync.Mutex 只有 Lock()和 Unlock() 方法,它們是成對存在的,且Lock后一定要執(zhí)行Unlock進行釋放鎖。所以可以使用 defer 語句釋放鎖,以保證鎖一定會被釋放。
func add(i int){ mutex.Lock() defer mutex.Unlock() sum += i }
上面例子是對 sum 寫操作時使用sync.Mutex 保證并發(fā)安全,當(dāng)多個協(xié)程進行讀取操作時,避免因并發(fā)產(chǎn)生讀取數(shù)據(jù)不正確,也是可以使用互斥鎖 sync.Mutex。
func getSum(){ mutex.Lock() defer mutex.Unlock() b:=sum return b }
多個協(xié)程 goroutine 同時讀寫的資源競爭問題解決,還需要考慮性能問題,每次讀寫共享資源都加鎖,也會導(dǎo)致性能低。
多個協(xié)程并發(fā)進行讀寫時會遇到以下情況:
寫時不能同時讀,易讀到臟數(shù)據(jù)
讀時不能同時寫,因為會導(dǎo)致結(jié)果不一致
讀時同時寫,因數(shù)據(jù)不變,無論多少個 goroutine 讀都是并發(fā)安全
使用讀寫鎖 sync.RWMutex 優(yōu)化代碼:
var mutex sync.RWMutex func readSum() int { mutex.RLock() defer mutex.RUnlock() b := sum return b }
讀寫鎖的性能比互斥鎖性能好。
為了能夠監(jiān)聽所有的協(xié)程的執(zhí)行,一旦所有的goroutine 都執(zhí)行完成,程序應(yīng)當(dāng)及時退出節(jié)省時間提高性能。通過使用 sync.WaitGroup 來解決。使用步驟如下:
聲明一個 sync.WaitGroup ,通過 add 方法增加計數(shù)器值,有幾個協(xié)程就計算幾個
每個協(xié)程結(jié)束后就調(diào)用 Done 方法,主要是讓計數(shù)器減1
最后調(diào)用 Wait 方法一直等待,直到計數(shù)器為 0 時,所有跟蹤的協(xié)程都執(zhí)行完畢
func run() { var wg sync.WaitGroup wg.Add(100) for i := 0; i < 100; i++ { go func() { defer wg.Done() add(10) }() } wg.Wait() }
通過 sync.WaitGroup 可以很好地跟蹤協(xié)程.
sync.Once 作用是讓代碼只執(zhí)行一次。詳細使用是調(diào)用方法 once.Do 方法,具體實現(xiàn):
func main(){ var once sync.once oneFunc := func(){ println("once func") } once.Do(oneFunc) }
sync.Once 適用于創(chuàng)建某個對象的單例、只加載一次的資源等只執(zhí)行一次的場景。
使用 sync.WaitGroup 主要是控制等待所有的協(xié)程都執(zhí)行完畢,才最終完成。但是當(dāng)遇到場景是,只有等待所有條件都準(zhǔn)備好才開始。sync.Cond 相當(dāng)于發(fā)號施令,只有通知執(zhí)行所有的協(xié)程才可以執(zhí)行,重點是所有協(xié)程需等待喚醒才可以開始。
所以 sync.Cond 具有阻塞協(xié)程和喚醒協(xié)程的功能。詳細的用法:
通過 sync.NewCond 函數(shù)生成一個 *sync.Cond,用于阻塞和喚醒協(xié)程
調(diào)用 cond.Wait() 方法阻塞當(dāng)前協(xié)程等待,需要注意調(diào)用 cond.Wait() 方法要加鎖
調(diào)用 cond.Broadcast() 后所有協(xié)程才開始執(zhí)行
func run() { cond := sync.NewCond(&sync.Mutex{}) var wg sync.WaitGroup wg.Add(101) for i := 0; i < 100; i++ { go func(num int) { defer wg.Done() fmt.Println(num, "號正在 awaiting......") cond.L.Lock() cond.Wait() //等待所有協(xié)程準(zhǔn)備完成 fmt.Println(num, "號開始跑……") cond.L.Unlock() }(i) } // 等待所有的協(xié)程都進入 wait 狀態(tài) time.Sleep(2*time.Second) go func() { defer wg.Done() // 所有都準(zhǔn)備完成,開始 cond.Broadcast() }() // 防止函數(shù)提前返回退出 wg.Wait() }
到此,相信大家對“GO中sync包自由控制并發(fā)的方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。