中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang中怎么實現并發控制

發布時間:2021-07-06 15:06:56 來源:億速云 閱讀:366 作者:Leah 欄目:大數據

Golang中怎么實現并發控制,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

Golang中通過go關鍵字就可開啟一個goroutine,因此,在Go中可以輕松寫出并發代碼。但是,如何對這些并發執行的groutines有效地控制?

提到并發控制,很多人可能最先想到的是鎖。Golang中同樣提供了鎖的相關機制,包括互斥鎖sync.Mutex,和讀寫鎖sync.RWMutex。除了鎖,還有原子操作sync/atomic等。但是,這些機制關注的重點是goroutines的并發數據安全性。而本文想討論的是goroutine的并發行為控制。

在goroutine并發行為控制中,有三種常見的方式,分別是WaitGroup、channel和Context。

WaitGroup

WaitGroup位于sync包下,它的使用方法如下。

func main() {  var wg sync.WaitGroup
 wg.Add(2) //添加需要完成的工作量2
 go func() {    wg.Done() //完成工作量1    fmt.Println("goroutine 1 完成工作!")  }()
 go func() {    wg.Done() //完成工作量1    fmt.Println("goroutine 2 完成工作!")  }()
 wg.Wait() //等待工作量2均完成  fmt.Println("所有的goroutine均已完成工作!")}
輸出://goroutine 2 完成工作!//goroutine 1 完成工作!//所有的goroutine均已完成工作!

WaitGroup這種并發控制方式尤其適用于:某任務需要多 goroutine 協同工作,每個 goroutine 只能做該任務的一部分,只有全部的 goroutine 都完成,任務才算是完成。因此,WaitGroup同名字的含義一樣,是一種等待的方式。

但是,在實際的業務中,有這么一種場景:當滿足某個要求時,需主動的通知某一個 goroutine 結束。比如我們開啟一個后臺監控goroutine,當不再需要監控時,就應該通知這個監控 goroutine 結束,不然它會一直空轉,造成泄漏。

Channel

對于上述場景,WaitGroup無能為力。那能想到的最簡單的方法:定義一個全局變量,在其它地方通過修改這個變量進行通知,后臺 goroutine 會不停的檢查這個變量,如果發現變量發生了變化,即自行關閉,但是這個方法未免有些笨拙。這種情況,channel+select可派上用場。

func main() {  exit := make(chan bool)
 go func() {    for {      select {      case <-exit:        fmt.Println("退出監控")        return      default:        fmt.Println("監控中")        time.Sleep(2 * time.Second)      }    }  }()
 time.Sleep(5 * time.Second)  fmt.Println("通知監控退出")  exit <- true
 //防止main goroutine過早退出  time.Sleep(5 * time.Second)}
輸出://監控中//監控中//監控中//通知監控退出//退出監控

這種 channel+select 的組合,是比較優雅的通知goroutine 結束的方式。

但是,該方案同樣存在局限性。試想,如果有多個 goroutine 都需要控制結束怎么辦?如果這些 goroutine 又衍生了其它更多的goroutine 呢?當然我們可以定義很多 channel 來解決這個問題,但是 goroutine 的關系鏈導致這種場景的復雜性。

Context

以上場景常見于CS架構模型下。在Go中,常常為每個client開啟單獨的goroutine(A)來處理它的一系列request,并且往往單個A中也會請求其他服務(啟動另一個goroutine B),B也可能會請求另外的goroutine C,C再將request發送給例如Databse的server。設想,當client斷開連接,那么與之相關聯的A、B、C均需要立即退出,系統才可回收A、B、C所占用的資源。退出A簡單,但是,如何通知B、C也退出呢?

這個時候,Context就出場了。

func A(ctx context.Context, name string)  {  go B(ctx ,name) //A調用了B  for {    select {    case <-ctx.Done():      fmt.Println(name, "A退出")      return    default:      fmt.Println(name, "A do something")      time.Sleep(2 * time.Second)    }  }}
func B(ctx context.Context, name string)  {  for {    select {    case <-ctx.Done():      fmt.Println(name, "B退出")      return    default:      fmt.Println(name, "B do something")      time.Sleep(2 * time.Second)    }  }}
func main() {  ctx, cancel := context.WithCancel(context.Background())
 go A(ctx, "【請求1】") //模擬client來了1個連接請求
 time.Sleep(3 * time.Second)  fmt.Println("client斷開連接,通知對應處理client請求的A,B退出")  cancel() //假設滿足某條件client斷開了連接,那么就傳播取消信號,ctx.Done()中得到取消信號
 time.Sleep(3 * time.Second)}
輸出://【請求1】 A do something//【請求1】 B do something//【請求1】 A do something//【請求1】 B do something//client斷開連接,通知對應處理client請求的A,B退出//【請求1】 B退出//【請求1】 A退出

示例中模擬了客戶端來了連接請求,相應開啟Goroutine A進行處理,A同時開啟了B處理,A和B都使用了 Context 進行跟蹤,當我們使用 cancel 函數通知取消時,這 2個 goroutine 都會被結束。

這就是 Context 的控制能力,它就像一個控制器一樣,按下開關后,所有基于這個 Context 或者衍生的子 Context 都會收到通知,這時就可以進行清理操作了,最終釋放 goroutine,這就優雅的解決了 goroutine 啟動后不可控的問題。

關于Golang中怎么實現并發控制問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汝城县| 安徽省| 柳河县| 射洪县| 铅山县| 班戈县| 乐亭县| 徐水县| 曲沃县| 额尔古纳市| 治多县| 侯马市| 宁都县| 静乐县| 靖宇县| 察雅县| 普宁市| 黄骅市| 轮台县| 石屏县| 周口市| 漾濞| 秦安县| 贵定县| 六安市| 青岛市| 五原县| 博爱县| 海伦市| 敦煌市| 临颍县| 简阳市| 安宁市| 彭州市| 兴文县| 尼木县| 海丰县| 富蕴县| 定南县| 枝江市| 西林县|