首頁 常見問題 go語言怎麼實現並發控制

go語言怎麼實現並發控制

Jun 08, 2023 pm 02:20 PM
go並發控制

go語言實現並發控制的方法:1、WaitGroup,多個goroutine的任務處理存在依賴或拼接關係;2、Channel,可以主動取消goroutine;多groutine中資料傳遞;代替WaitGroup的工作,滿足Context的功能;3、Context,多層級groutine之間的訊號傳播,包括元資料傳播,取消訊號傳播、逾時控制等。

go語言怎麼實現並發控制

本文的操作環境:Windows10系統、go1.20版本、dell g3電腦。

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 啟動後不可控的問題。

關於Context的詳細用法,不在本文討論範圍。後續會出專門對Context包的講解文章,敬請關注。

總結

本文列舉了三種Golang中並發行為控制模式。模式之間沒有好壞之分,只在於不同的場景用恰當的方案。實際專案中,往往多種方式混合使用。

  • WaitGroup:多個goroutine的任務處理存在依賴或拼接關係。
  • channel select:可以主動取消goroutine;多groutine中資料傳遞;channel可以取代WaitGroup的工作,但會增加程式碼邏輯複雜性;多channel可以滿足Context的功能,同樣,也會讓程式碼邏輯變得複雜。
  • Context:多層級groutine之間的訊號傳播(包含元資料傳播,取消訊號傳播、逾時控制等)。

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

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

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

以上是go語言怎麼實現並發控制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)