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

Golang sync包中errgroup的使用詳解

 更新時(shí)間:2023年05月12日 11:49:35   作者:人艱不拆_zmc  
Go 語(yǔ)言為我們提供了豐富的并發(fā)原語(yǔ),且大多數(shù)都位于 sync 包下,今天我們來(lái)探討一下該庫(kù)下的原語(yǔ)之一:errgroup,感興趣的小伙伴可以了解一下

1、初識(shí) errgroup

WaitGroup 主要用于控制任務(wù)組下的并發(fā)子任務(wù)。它的具體做法就是,子任務(wù) goroutine 執(zhí)行前通過(guò) Add 方法添加任務(wù)數(shù)目,子任務(wù) goroutine 結(jié)束時(shí)調(diào)用 Done 標(biāo)記已完成任務(wù)數(shù),主任務(wù) goroutine 通過(guò) Wait 方法等待所有的任務(wù)完成后才能執(zhí)行后續(xù)邏輯。

package main
  
 import (
     "net/http"
     "sync"
 )
  
 func main() {
    var wg sync.WaitGroup
    var urls = []string{
        "http://www.golang.org/",
        "http://www.baidu.com/",
        "http://www.bokeyuan12111.com/",
    }
    for _, url := range urls {
        wg.Add(1)
        go func(url string) {
            defer wg.Done()
            resp, err := http.Get(url)
            if err != nil {
                return
            }
            resp.Body.Close()
        }(url)
    }
    wg.Wait()
}

在以上示例代碼中,我們通過(guò)三個(gè) goroutine 去并發(fā)的請(qǐng)求 url,直到所有的子任務(wù) goroutine 均完成訪問(wèn),主任務(wù) goroutine 下的 wg.Wait 才會(huì)停止阻塞。

但在實(shí)際的項(xiàng)目代碼中,子任務(wù) goroutine 的執(zhí)行并不總是順風(fēng)順?biāo)鼈円苍S會(huì)產(chǎn)生 error。而 WaitGroup 并沒(méi)有告訴我們?cè)谧?goroutine 發(fā)生錯(cuò)誤時(shí),如何將其拋給主任務(wù) groutine。

這個(gè)時(shí)候可以考慮使用 errgroup

package main
  
 import (
     "fmt"
     "net/http"
  
     "golang.org/x/sync/errgroup"
 )
  
func main() {
    var urls = []string{
        "http://www.golang.org/",
        "http://www.baidu.com/",
        "http://www.bokeyuan12111.com/",
    }
    g := new(errgroup.Group)
    for _, url := range urls {
        url := url
        g.Go(func() error {
            resp, err := http.Get(url)
            if err != nil {
                fmt.Println(err)
                return err
            }
            fmt.Printf("get [%s] success: [%d] \n", url, resp.StatusCode)
            return resp.Body.Close()
        })
    }
    if err := g.Wait(); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("All success!")
    }
}

結(jié)果如下:

get [http://www.baidu.com/] success: [200]
Get "http://www.bokeyuan12111.com/": dial tcp: lookup www.bokeyuan12111.com: no such host
Get "http://www.golang.org/": dial tcp 142.251.42.241:80: i/o timeout
Get "http://www.bokeyuan12111.com/": dial tcp: lookup www.bokeyuan12111.com: no such host

可以看到,執(zhí)行獲取www.bokeyuan12111.com和www.golang.org兩個(gè) url 的子 groutine 均發(fā)生了錯(cuò)誤,在主任務(wù) goroutine 中成功捕獲到了第一個(gè)錯(cuò)誤信息。

除了 擁有 WaitGroup 的控制能力 和 錯(cuò)誤傳播 的功能之外,errgroup 還有最重要的 context 反向傳播機(jī)制,我們來(lái)看一下它的設(shè)計(jì)。

2、errgroup 源碼解析

errgroup 的設(shè)計(jì)非常精練,全部代碼如下

type Group struct {
     cancel func()
  
     wg sync.WaitGroup
  
     errOnce sync.Once
     err     error
 }
  
func WithContext(ctx context.Context) (*Group, context.Context) {
    ctx, cancel := context.WithCancel(ctx)
    return &Group{cancel: cancel}, ctx
}
 
func (g *Group) Wait() error {
    g.wg.Wait()
    if g.cancel != nil {
        g.cancel()
    }
    return g.err
}
 
func (g *Group) Go(f func() error) {
    g.wg.Add(1)
 
    go func() {
        defer g.wg.Done()
 
        if err := f(); err != nil {
            g.errOnce.Do(func() {
                g.err = err
                if g.cancel != nil {
                    g.cancel()
                }
            })
        }
    }()
}

可以看到,errgroup 的實(shí)現(xiàn)依靠于結(jié)構(gòu)體 Group,它通過(guò)封裝 sync.WaitGroup,繼承了 WaitGroup 的特性,在 Go() 方法中新起一個(gè)子任務(wù) goroutine,并在 Wait() 方法中通過(guò) sync.WaitGroup 的 Wait 進(jìn)行阻塞等待。

同時(shí) Group 利用 sync.Once 保證了它有且僅會(huì)保留第一個(gè)子 goroutine 錯(cuò)誤。

最后,Group 通過(guò)嵌入 context.WithCancel 方法產(chǎn)生的 cancel 函數(shù),能夠在子 goroutine 發(fā)生錯(cuò)誤時(shí),及時(shí)通過(guò)調(diào)用 cancle 函數(shù),將 Context 的取消信號(hào)及時(shí)傳播出去。當(dāng)然,這一特性需要用戶代碼的配合。

3、errgroup 上下文取消

在 errgroup 的文檔(https://pkg.go.dev/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup#example-Group-Pipeline)中,它基于 Go 官方文檔的 pipeline( https://blog.golang.org/pipelines) ,實(shí)現(xiàn)了一個(gè)任務(wù)組 goroutine 中上下文取消(Context cancelation)演示的示例。但該 Demo 的前提知識(shí)略多,本文這里基于其思想,提供一個(gè)易于理解的使用示例。

package main
 
import (
    "context"
    "fmt"
 
    "golang.org/x/sync/errgroup"
)
 
func main() {
 
    g, ctx := errgroup.WithContext(context.Background())
    dataChan := make(chan int, 20)
 
    // 數(shù)據(jù)生產(chǎn)端任務(wù)子 goroutine
    g.Go(func() error {
        defer close(dataChan)
        for i := 1; ; i++ {
            if i == 10 {
                return fmt.Errorf("data 10 is wrong")
            }
            dataChan <- i
            fmt.Println(fmt.Sprintf("sending %d", i))
        }
    })
 
    // 數(shù)據(jù)消費(fèi)端任務(wù)子 goroutine
    for i := 0; i < 3; i++ {
        g.Go(func() error {
            for j := 1; ; j++ {
                select {
                case <-ctx.Done():
                    return ctx.Err()
                case number := <-dataChan:
                    fmt.Println(fmt.Sprintf("receiving %d", number))
                }
            }
        })
    }
 
    // 主任務(wù) goroutine 等待 pipeline 結(jié)束數(shù)據(jù)流
    err := g.Wait()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("main goroutine done!")
}

在以上示例中,我們模擬了一個(gè)數(shù)據(jù)傳送管道。在數(shù)據(jù)的生產(chǎn)與消費(fèi)任務(wù)集中,有四個(gè)子任務(wù) goroutine:一個(gè)生產(chǎn)數(shù)據(jù)的 goroutine,三個(gè)消費(fèi)數(shù)據(jù)的 goroutine。當(dāng)數(shù)據(jù)生產(chǎn)方存在錯(cuò)誤數(shù)據(jù)時(shí)(數(shù)據(jù)等于 10 ),我們停止數(shù)據(jù)的生產(chǎn)與消費(fèi),并將錯(cuò)誤拋出,回到 main goroutine 的執(zhí)行邏輯中。

可以看到,因?yàn)?errgroup 中的 Context cancle 函數(shù)的嵌入,我們?cè)谧尤蝿?wù) goroutine 中也能反向控制任務(wù)上下文。

程序的某一次運(yùn)行,輸出結(jié)果如下:

sending 1
sending 2
sending 3
sending 4
sending 5
sending 6
sending 7
sending 8
sending 9
receiving 1
receiving 3
receiving 2
receiving 4
data 10 is wrong
main goroutine done!

4、總結(jié)

errgroup 是 Go 官方的并發(fā)原語(yǔ)補(bǔ)充庫(kù),相對(duì)于標(biāo)準(zhǔn)庫(kù)中提供的原語(yǔ)而言,顯得沒(méi)那么核心。這里總結(jié)一下 errgroup 的特性。

  • 繼承了 WaitGroup 的功能
  • 錯(cuò)誤傳播:能夠返回任務(wù)組中發(fā)生的第一個(gè)錯(cuò)誤,但有且僅能返回該錯(cuò)誤
  • context 信號(hào)傳播:如果子任務(wù) goroutine 中有循環(huán)邏輯,則可以添加 ctx.Done 邏輯,此時(shí)通過(guò) context 的取消信號(hào),提前結(jié)束子任務(wù)執(zhí)行。

到此這篇關(guān)于Golang sync包中errgroup的使用詳解的文章就介紹到這了,更多相關(guān)Golang errgroup內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解Golang的函數(shù)特性

    一文詳解Golang的函數(shù)特性

    函數(shù)是?Golang?中非常重要的組成部分之一,它們提供了代碼的可重用性和組織性。在本文中,我們將深入了解?Golang?函數(shù)的多個(gè)方面,希望對(duì)大家有所幫助
    2023-04-04
  • 用Go獲取短信驗(yàn)證碼的示例代碼

    用Go獲取短信驗(yàn)證碼的示例代碼

    要用Go獲取短信驗(yàn)證碼,通常需要連接到一個(gè)短信服務(wù)提供商的API,并通過(guò)該API發(fā)送請(qǐng)求來(lái)獲取驗(yàn)證碼,由于不同的短信服務(wù)提供商可能具有不同的API和授權(quán)方式,我將以一個(gè)簡(jiǎn)單的示例介紹如何使用Go語(yǔ)言來(lái)獲取短信驗(yàn)證碼,需要的朋友可以參考下
    2023-07-07
  • Golang實(shí)現(xiàn)簡(jiǎn)單http服務(wù)器的示例詳解

    Golang實(shí)現(xiàn)簡(jiǎn)單http服務(wù)器的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用Golang實(shí)現(xiàn)簡(jiǎn)單http服務(wù)器,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Golang有一定的幫助,需要的可以參考一下
    2023-03-03
  • Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件詳解

    Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件詳解

    這篇文章主要給大家介紹了關(guān)于Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件的相關(guān)資料,并介紹了golang如何讓編譯生產(chǎn)的二進(jìn)制文件變小,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • golang模擬實(shí)現(xiàn)帶超時(shí)的信號(hào)量示例代碼

    golang模擬實(shí)現(xiàn)帶超時(shí)的信號(hào)量示例代碼

    這篇文章主要給大家介紹了關(guān)于golang模擬實(shí)現(xiàn)帶超時(shí)的信號(hào)量的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • 詳解Go語(yǔ)言strconv與其他基本數(shù)據(jù)類型轉(zhuǎn)換函數(shù)的使用

    詳解Go語(yǔ)言strconv與其他基本數(shù)據(jù)類型轉(zhuǎn)換函數(shù)的使用

    這篇文章將以 string 類型為中心,通過(guò) strconv 標(biāo)準(zhǔn)庫(kù),介紹其與其他基本數(shù)據(jù)類型相互轉(zhuǎn)換的函數(shù)。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-12-12
  • Golang實(shí)現(xiàn)協(xié)程超時(shí)控制的方式總結(jié)

    Golang實(shí)現(xiàn)協(xié)程超時(shí)控制的方式總結(jié)

    我們知道,go協(xié)程如果不做好處理,很容易造成內(nèi)存泄漏,所以對(duì)goroutine做超時(shí)控制,才能有效避免這種情況發(fā)生,本文為大家整理了兩個(gè)常見(jiàn)的Golang超時(shí)控制方法,需要的可以收藏一下
    2023-05-05
  • GO 使用Webhook 實(shí)現(xiàn)github 自動(dòng)化部署的方法

    GO 使用Webhook 實(shí)現(xiàn)github 自動(dòng)化部署的方法

    這篇文章主要介紹了GO 使用Webhook 實(shí)現(xiàn)github 自動(dòng)化部署的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • golang在GRPC中設(shè)置client的超時(shí)時(shí)間

    golang在GRPC中設(shè)置client的超時(shí)時(shí)間

    這篇文章主要介紹了golang在GRPC中設(shè)置client的超時(shí)時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Go語(yǔ)言實(shí)現(xiàn)彩色輸出示例詳解

    Go語(yǔ)言實(shí)現(xiàn)彩色輸出示例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言實(shí)現(xiàn)彩色輸出示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09

最新評(píng)論