欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言動(dòng)態(tài)并發(fā)控制sync.WaitGroup的靈活運(yùn)用示例詳解

 更新時(shí)間:2023年11月22日 11:42:29   作者:Go先鋒  
本文將講解 sync.WaitGroup 的使用方法、原理以及在實(shí)際項(xiàng)目中的應(yīng)用場(chǎng)景,用清晰的代碼示例和詳細(xì)的注釋,助力讀者掌握并發(fā)編程中等待組的使用技巧

概述

在并發(fā)編程中,控制主程序等待所有 Goroutine 完成任務(wù)是一項(xiàng)關(guān)鍵任務(wù)。Go 語(yǔ)言提供了 sync.WaitGroup 來(lái)解決這一問(wèn)題。

1. 基本使用

1.1 初始化和添加計(jì)數(shù)

package main
import (
  "fmt"
  "sync"
  "time"
)
func main() {
  var wg sync.WaitGroup
  for i := 1; i <= 3; i++ {
    wg.Add(1)
    go worker(i, &wg)
  }
  wg.Wait()
  fmt.Println("All workers have completed.")
}
func worker(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Worker %d started\n", id)
  time.Sleep(2 * time.Second)
  fmt.Printf("Worker %d completed\n", id)
}

在上面示例中,用一個(gè) sync.WaitGroup 實(shí)例 wg,然后使用 wg.Add(1) 來(lái)增加計(jì)數(shù),表示有一個(gè) Goroutine 需要等待。

在每個(gè) Goroutine 的結(jié)束處,使用 defer wg.Done() 來(lái)減少計(jì)數(shù),表示一個(gè) Goroutine 已完成。

最后,用 wg.Wait() 來(lái)等待所有 Goroutine 完成。

1.2 處理錯(cuò)誤

package main
import (
  "fmt"
  "sync"
  "time"
)
func main() {
  var wg sync.WaitGroup
  for i := 1; i <= 3; i++ {
    wg.Add(1)
    go workerWithError(i, &wg)
  }
  wg.Wait()
  fmt.Println("All workers have completed.")
}
func workerWithError(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Worker %d started\n", id)
  time.Sleep(2 * time.Second)
  // 模擬錯(cuò)誤發(fā)生
  if id == 2 {
    fmt.Printf("Worker %d encountered an error\n", id)
    return
  }
  fmt.Printf("Worker %d completed\n", id)
}

有時(shí)候,需要在 Goroutine 中處理錯(cuò)誤。在這個(gè)示例中,當(dāng) id 為 2 時(shí),模擬了一個(gè)錯(cuò)誤的情況。

通過(guò)在錯(cuò)誤發(fā)生時(shí)提前返回,可以確保計(jì)數(shù)正確減少,避免等待組出現(xiàn)死鎖。

2. 多級(jí)等待組

2.1 嵌套使用

package main
import (
  "fmt"
  "sync"
  "time"
)
func main() {
  var outerWG sync.WaitGroup
  var innerWG sync.WaitGroup
  for i := 1; i <= 2; i++ {
    outerWG.Add(1)
    go outerWorker(i, &outerWG, &innerWG)
  }
  outerWG.Wait()
  fmt.Println("All outer workers have completed.")
}
func outerWorker(id int, outerWG, innerWG *sync.WaitGroup) {
  defer outerWG.Done()
  fmt.Printf("Outer Worker %d started\n", id)
  for j := 1; j <= 3; j++ {
    innerWG.Add(1)
    go innerWorker(id, j, innerWG)
  }
  innerWG.Wait()
  fmt.Printf("Outer Worker %d completed\n", id)
}
func innerWorker(outerID, innerID int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Inner Worker %d of Outer Worker %d started\n", innerID, outerID)
  time.Sleep(2 * time.Second)
  fmt.Printf("Inner Worker %d of Outer Worker %d completed\n", innerID, outerID)
}

在示例中,使用了嵌套的 sync.WaitGroup。

外部的等待組 outerWG 等待所有外部 Goroutine 完成,而每個(gè)外部 Goroutine 內(nèi)部的 innerWG 則等待其內(nèi)部的所有 Goroutine 完成。

2.2 動(dòng)態(tài)添加等待組

package main
import (
  "fmt"
  "sync"
  "time"
)
func main() {
  var dynamicWG sync.WaitGroup
  for i := 1; i <= 3; i++ {
    dynamicWG.Add(1)
    go dynamicWorker(i, &dynamicWG)
  }
  // 模擬動(dòng)態(tài)添加更多任務(wù)
  time.Sleep(1 * time.Second)
  for i := 4; i <= 6; i++ {
    dynamicWG.Add(1)
    go dynamicWorker(i, &dynamicWG)
  }
  dynamicWG.Wait()
  fmt.Println("All dynamic workers have completed.")
}
func dynamicWorker(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Dynamic Worker %d started\n", id)
  time.Sleep(2 * time.Second)
  fmt.Printf("Dynamic Worker %d completed\n", id)
}

在上述示例中,創(chuàng)建了一個(gè)等待組 dynamicWG,然后在運(yùn)行時(shí)動(dòng)態(tài)添加了更多的任務(wù)。

用這種方式,可以動(dòng)態(tài)地管理需要等待的 Goroutine 數(shù)量。   

3. 超時(shí)處理

3.1 帶超時(shí)的等待

package main
import (
  "fmt"
  "sync"
  "time"
)
func main() {
  var timeoutWG sync.WaitGroup
  for i := 1; i <= 3; i++ {
    timeoutWG.Add(1)
    go timeoutWorker(i, &timeoutWG)
  }
  // 等待最多5秒,超時(shí)則不再等待
  timeout := time.After(5 * time.Second)
  done := make(chan struct{})
  go func() {
    timeoutWG.Wait()
    close(done)
  }()
  select {
  case <-done:
    fmt.Println("All timeout workers have completed.")
  case <-timeout:
    fmt.Println("Timeout reached. Not all workers have completed.")
  }
}
func timeoutWorker(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Timeout Worker %d started\n", id)
  time.Sleep(time.Duration(id) * time.Second)
  fmt.Printf("Timeout Worker %d completed\n", id)
}

在上面示例中,用 time.After 創(chuàng)建了一個(gè) 5 秒的超時(shí)通道。

在另一個(gè) Goroutine 中監(jiān)聽(tīng)等待組的完成情況,可以在超時(shí)或任務(wù)完成時(shí)得知等待的最終結(jié)果。

3.2 處理超時(shí)錯(cuò)誤

package main
import (
  "errors"
  "fmt"
  "sync"
  "time"
)
func main() {
  var timeoutWG sync.WaitGroup
  for i := 1; i <= 3; i++ {
    timeoutWG.Add(1)
    go timeoutWorkerWithError(i, &timeoutWG)
  }
  // 等待最多5秒,超時(shí)則返回錯(cuò)誤
  err := waitWithTimeout(&timeoutWG, 5*time.Second)
  if err != nil {
    fmt.Printf("Timeout reached. Not all workers have completed. Error: %v\n", err)
  } else {
    fmt.Println("All timeout workers have completed.")
  }
}
func timeoutWorkerWithError(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Timeout Worker %d started\n", id)
  time.Sleep(time.Duration(id) * time.Second)
  // 模擬錯(cuò)誤發(fā)生
  if id == 2 {
    fmt.Printf("Timeout Worker %d encountered an error\n", id)
    return
  }
  fmt.Printf("Timeout Worker %d completed\n", id)
}
func waitWithTimeout(wg *sync.WaitGroup, timeout time.Duration) error {
  done := make(chan struct{})
  go func() {
    defer close(done)
    wg.Wait()
  }()
  select {
  case <-done:
    return nil
  case <-time.After(timeout):
    return errors.New("timeout reached")
  }
}

有時(shí)候,希望在程序超時(shí)的時(shí)候返回一個(gè)錯(cuò)誤。

在這個(gè)示例中,用封裝等待組的超時(shí)檢查,可以在主程序中獲得一個(gè)清晰的錯(cuò)誤提示。

總結(jié)

通過(guò)討論 sync.WaitGroup 的基本用法、避免常見(jiàn)錯(cuò)誤以及實(shí)際應(yīng)用,深入了解了這個(gè)強(qiáng)大的同步工具。

在 Go 語(yǔ)言并發(fā)編程中,合理使用 sync.WaitGroup 能夠優(yōu)雅地處理并發(fā)等待,確保主程序在所有任務(wù)完成后再繼續(xù)執(zhí)行。

以上就是Go語(yǔ)言動(dòng)態(tài)并發(fā)控制sync.WaitGroup的靈活運(yùn)用示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Go sync.WaitGroup動(dòng)態(tài)并發(fā)控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語(yǔ)言中decimal的用法詳解

    go語(yǔ)言中decimal的用法詳解

    本文主要介紹了go語(yǔ)言中decimal的用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 詳解Golang函數(shù)式選項(xiàng)(Functional?Options)模式

    詳解Golang函數(shù)式選項(xiàng)(Functional?Options)模式

    什么是函數(shù)式選項(xiàng)模式,為什么要這么寫(xiě),這個(gè)編程模式解決了什么問(wèn)題呢?其實(shí)就是為了解決動(dòng)態(tài)靈活的配置不同的參數(shù)的問(wèn)題。下面通過(guò)本文給大家介紹Golang函數(shù)式選項(xiàng)(Functional?Options)模式的問(wèn)題,感興趣的朋友一起看看吧
    2021-12-12
  • 一文詳解Golang中new和make的區(qū)別

    一文詳解Golang中new和make的區(qū)別

    在Go語(yǔ)言中,new和make是兩個(gè)用于創(chuàng)建對(duì)象的內(nèi)建函數(shù)。本文將詳細(xì)介紹new和make的區(qū)別,并通過(guò)多個(gè)方面的分析和代碼示例,幫助大家理解它們的使用場(chǎng)景
    2023-05-05
  • 利用Golang實(shí)現(xiàn)TCP連接的雙向拷貝詳解

    利用Golang實(shí)現(xiàn)TCP連接的雙向拷貝詳解

    公司中遇到了一個(gè)使用golang編寫(xiě)的agent程序,所以這篇文章主要給大家介紹了關(guān)于利用Go如何實(shí)現(xiàn)TCP連接的雙向拷貝的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考,下面隨著小編來(lái)一起看看吧。
    2017-09-09
  • Go語(yǔ)言二維數(shù)組的傳參方式

    Go語(yǔ)言二維數(shù)組的傳參方式

    這篇文章主要介紹了Go語(yǔ)言二維數(shù)組的傳參方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Golang使用gob實(shí)現(xiàn)結(jié)構(gòu)體的序列化過(guò)程詳解

    Golang使用gob實(shí)現(xiàn)結(jié)構(gòu)體的序列化過(guò)程詳解

    Golang struct類型數(shù)據(jù)序列化用于網(wǎng)絡(luò)傳輸數(shù)據(jù)或在磁盤上寫(xiě)入數(shù)據(jù)。在分布式系統(tǒng)中,一端生成數(shù)據(jù)、然后序列化、壓縮和發(fā)送;在另一端,接收數(shù)據(jù)、然后解壓縮、反序列化和處理數(shù)據(jù),整個(gè)過(guò)程必須快速有效
    2023-03-03
  • 解決golang http重定向失效的問(wèn)題

    解決golang http重定向失效的問(wèn)題

    這篇文章主要介紹了解決golang http重定向失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go切片導(dǎo)致rand.Shuffle產(chǎn)生重復(fù)數(shù)據(jù)的原因與解決方案

    Go切片導(dǎo)致rand.Shuffle產(chǎn)生重復(fù)數(shù)據(jù)的原因與解決方案

    在 Go 語(yǔ)言的實(shí)際開(kāi)發(fā)中,切片(slice)是一種非常靈活的數(shù)據(jù)結(jié)構(gòu),然而,由于其底層數(shù)據(jù)共享的特性,在某些情況下可能會(huì)導(dǎo)致意想不到的 Bug,本文將詳細(xì)分析 rand.Shuffle 之后,切片中的數(shù)據(jù)出現(xiàn)重復(fù)的問(wèn)題,探討其根本原因,并給出最佳解決方案,需要的朋友可以參考下
    2025-02-02
  • 執(zhí)行g(shù)o?build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?directory?or?any?parent?directory

    執(zhí)行g(shù)o?build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?dir

    本文主要為大家介紹了執(zhí)行g(shù)o build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?directory?or?any?parent?directory解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Golang算法問(wèn)題之?dāng)?shù)組按指定規(guī)則排序的方法分析

    Golang算法問(wèn)題之?dāng)?shù)組按指定規(guī)則排序的方法分析

    這篇文章主要介紹了Golang算法問(wèn)題之?dāng)?shù)組按指定規(guī)則排序的方法,結(jié)合實(shí)例形式分析了Go語(yǔ)言數(shù)組排序相關(guān)算法原理與操作技巧,需要的朋友可以參考下
    2017-02-02

最新評(píng)論