日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

golang 多协程的同步方法总结

發布時間:2024/8/23 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 golang 多协程的同步方法总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前用 go 寫一個小工具的時候, 用到了多個協程之間的通信, 當時隨手查了查, 結果查出來一大坨, 簡單記錄一下. golang中多個協程之間是如何進行通信及數據同步的嘞.

共享變量

一個最簡單, 最容易想到的, 就是通過全局變量的方式, 多個協程讀寫同一個變量. 但對同一個變量的更改, 就不得不加鎖了, 否則極易引發數據問題. 一般系統庫都提供基本的鎖, go 也提供了.

package mainimport ("fmt""sync""time" )var num = 0 // 互斥鎖 var mutex = sync.Mutex{} // 讀寫鎖 var rwMutex = sync.RWMutex{}func main() {for i := 0; i < 100; i++ {go incrNum()}time.Sleep(2)fmt.Println(num) }func incrNum() {mutex.Lock()num = num + 1mutex.Unlock() }

僅執行一次

當查詢鎖查到sync這個模塊時, 發現它下面的對象并沒有幾個, 都是針對協程同步的各個方面給出的解決方案. 所以我就一個一個看文檔試了試.

當你需要對環境, 連接池等等資源進行初始化時, 這種操作只需要執行一次, 這時候就需要它了. sync.Once對象可以保證僅執行一次. 和 init 方法有些類似, 不過 init 方法是在模塊首次加載時執行, 而sync.Once是在首次調用時執行. (其實現就是一個計數器加一個互斥鎖)

package mainimport ("fmt""sync""time" )var num = 0 var once = sync.Once{}func main() {for i := 0; i < 100; i++ {go once.Do(incrNum)}time.Sleep(2)fmt.Println(num) }func incrNum() {num = num + 1 }

等待其他協程處理

某個協程需要等第一階段的所有協程處理完畢, 才能開始執行第二階段. 這個時候, 等待其他協程就可以通過sync.WaitGroup 來實現. (當然, 也可以通過一個共享計數器變量來實現).

package mainimport ("fmt""sync" )var waitGroup = sync.WaitGroup{}func main() {for i := 0; i < 100; i++ {go incrNum()}// 等待其他協程處理完畢(共享變量為0)waitGroup.Wait()fmt.Println("don") }func incrNum() {// 增加需要等待的協程數量(共享變量+1)waitGroup.Add(1)// do something// 標記當前協程處理完成(共享變量-1)waitGroup.Done() }

消息通知

多個協程啟動時, 等待某個命令到來時執行命令, 喚醒等待協程. go 對此類操作也進行了處理, 感覺好貼心哦. 但是經過測試, 即使沒有空閑的協程, 喚醒命令同樣能夠發出去, 所以需要注意一下.

package mainimport ("sync" )var mutex = &sync.Mutex{} var cond = sync.NewCond(mutex)func main() {for i := 0; i < 100; i++ {go incrNum()}// 發送命令給一個隨機獲得鎖的協程cond.Signal()// 發送命令給所有獲得鎖的協程cond.Broadcast() }func incrNum() {// 獲取鎖, 標識當前協程可以處理命令cond.L.Lock()// 可添加退出執行命令隊列的條件for true {// 等待命令cond.Wait()// do something}// 釋放鎖, 標記命令處理完畢, 退出協程cond.L.Unlock() }

多協程 map

普通的 map 在多協程操作時, 是不支持并發寫入的. go貼心的給封裝了支持并發寫入的map. 同時也提供了針對map的基本操作.

package mainimport ("fmt""sync""time" )var m = sync.Map{}func main() {for i := 0; i < 100; i++ {go func() {m.Store("1", 1)}()}time.Sleep(time.Second * 2)// 遍歷 mapm.Range(func(key, value interface{}) bool {// 返回 false 結束遍歷return true})// 讀取變量, 若不存在則設置m.LoadOrStore("1", 3)// 刪除 keym.Delete("1")// 讀取變量load, _ := m.Load("1")fmt.Println(load) }

多協程對象池

對于數據庫連接池應該并不陌生. 而sync.Pool對象是go封裝的協程安全的對象池. 對象池的使用十分簡單, 存/取

package mainimport ("sync" )var p = sync.Pool{// 當池子中沒有對象了, 用于創建新對象New: func() interface {}{return "3"}, }func main() {// 從池子中獲取一個對象r := p.Get()// 用完后將對象放回池子中p.Put(r) }

sync 簡單總結

針對go系統的sync模塊, 提供的基礎功能如下:

  • 互斥鎖 Mutex
  • 讀寫鎖 RWMutex
  • 函數單次執行 Once
  • 協程執行等待 WaitGroup
  • 協程消息通知 Cond
  • 多協程 map Map
  • 多協程對象池 Pool
  • 幾個都簡單試過之后, 發現sync模塊針對常用的幾個多協程工具進行了封裝, 想來可以基本滿足日常使用了.

    終極通信-channel

    channel是一個協程安全的通信管道, 簡單理解為數據從一側放入, 從另一側拿出. 這玩意感覺能玩出花來, 還不太理解, 留到國慶研究.

    總結

    以上是生活随笔為你收集整理的golang 多协程的同步方法总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。