Go語言擴(kuò)展原語之ErrGroup的用法詳解
概述
除標(biāo)準(zhǔn)庫中提供的同步原語外,Go
語言還在子倉庫sync
中提供了4種擴(kuò)展原語:
golang/sync/errgroup.Group
golang/sync/semaphore.Weighted
golang/sync/singleflight.Group
golang/sync/syncmap.Map
其中 golang/sync/syncmap.Map
在 Go1.9
中移植到了標(biāo)準(zhǔn)庫中。
接下來介紹Go
語言在擴(kuò)展包中提供的3種同步原語 —— golang/sync/errgroup.Group
ErrGroup
golang/sync/errgroup.Group
為我們在一組 Goroutine
中提供了同步、錯(cuò)誤傳播以及上下文取消功能,我們可以使用這種方式并行獲取網(wǎng)頁數(shù)據(jù):
var g errgroup.Group var urls = []string{ "http://www.golang.org", "http://www.google.com" } for i := range urls { url := urls[i] g.Go(func() error { resp, err := http.Get(url) if err == nil { resp.Body.Close() } return err }) } if err := g.Wait(); err == nil { fmt.Println("Successfully fetched all URLs.") }
golang/sync/errgroup.Group.Go
方法能夠創(chuàng)建一個(gè) Goroutine
并在其中執(zhí)行傳入的函數(shù),而 golang/sync/errgroup.Group.Wait
會(huì)等待所有 Goroutine
返回,該方法的不同返回結(jié)果有不同的含義:
- 如果返回錯(cuò)誤 —— 這一組
Goroutine
最少返回一個(gè)錯(cuò)誤 - 如果返回空值 —— 所有
Goroutine
都成功執(zhí)行
結(jié)構(gòu)體
golang/sync/errgroup.Group
結(jié)構(gòu)體有 3
個(gè)比較重要的部分組成
cancel
—— 創(chuàng)建context.Context
時(shí)返回的取消函數(shù),用于在多個(gè)Goroutine
之間同步取消信號(hào)wg
—— 用于等待一組Goroutine
完成子任務(wù)的同步原語errOnce
—— 用于保證只接收一個(gè)子任務(wù)
返回的錯(cuò)誤
type Group struct { cancel func() wg sync.WaitGroup errOnce sync.Once err error }
這些字段共同組成了 golang/sync/errgroup.Group
結(jié)構(gòu)體并為我提供同步、錯(cuò)誤傳播以及上下文取消等功能。
接口
我們能通過 golang/sync/errgroup.WithContext
構(gòu)造器創(chuàng)新的 golang/sync/errgroup.Group
結(jié)構(gòu)體:
func WithContext(ctx context.Context) (*Group, context.Context) { ctx, cancel := context.WithCancel(ctx) return &Group{cancel: cancel}, ctx }
運(yùn)行新的并行子任務(wù)需要使用 golang/sync/errgroup.Group.Go
方法,這個(gè)方法的執(zhí)行過程如下:
- 調(diào)用
sync.WaitGroup.Add
增加待處理的任務(wù) - 創(chuàng)建新的
Goroutine
并運(yùn)行子任務(wù) - 返回錯(cuò)誤時(shí)及時(shí)調(diào)用
cancel
并對err
賦值,只有最早返回的錯(cuò)誤才會(huì)被上游感知到,后續(xù)錯(cuò)誤都會(huì)被舍棄。
func (g *Group) Go(){ 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() } }) } }() } func (g *Group) Wait() error { g.wg.Wait() if g.cancel != nil { g.cancel() } return g.err }
另一個(gè)用于等待的 golang/sync/errgroup.Group.Wait
方法只是調(diào)用了 sync.WaitGroup.Wait
,在子任務(wù)全部完成時(shí)取消 context.Context 并返回可能出現(xiàn)的錯(cuò)誤。
小結(jié)
golang/sync/errgroup.Group
的實(shí)現(xiàn)沒有涉及底層和運(yùn)行包中的API
,它只是封裝了基本同步語義以提供更加復(fù)雜的功能。我們在使用它時(shí)需要注意兩個(gè)問題:
golang/sync/errgroup.Group
在出現(xiàn)錯(cuò)誤或者等待結(jié)束后,會(huì)調(diào)用context.Context
的cancel
方法同步取消信號(hào)- 只有第一個(gè)出現(xiàn)的錯(cuò)誤才會(huì)被返回,剩余錯(cuò)誤會(huì)被直接丟棄
到此這篇關(guān)于Go語言擴(kuò)展原語之ErrGroup的用法詳解的文章就介紹到這了,更多相關(guān)Go ErrGroup內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解golang執(zhí)行Linux shell命令完整場景下的使用方法
本文主要介紹了golang執(zhí)行Linux shell命令完整場景下的使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06golang 40行代碼實(shí)現(xiàn)通用協(xié)程池
golang協(xié)程機(jī)制很方便的解決了并發(fā)編程的問題,但是協(xié)程并不是沒有開銷的,所以也需要適當(dāng)限制一下數(shù)量。這篇文章主要介紹了golang 40行代碼實(shí)現(xiàn)通用協(xié)程池,需要的朋友可以參考下2018-08-08Go語言同步與異步執(zhí)行多個(gè)任務(wù)封裝詳解(Runner和RunnerAsync)
這篇文章主要給大家介紹了關(guān)于Go語言同步與異步執(zhí)行多個(gè)任務(wù)封裝(Runner和RunnerAsync)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01Go 循環(huán)結(jié)構(gòu)for循環(huán)使用教程全面講解
這篇文章主要為大家介紹了Go 循環(huán)結(jié)構(gòu)for循環(huán)使用全面講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10